2021-02-21
모든 입력 스트림의 최상위 클래스로 모든 바이트 기반의 입력 스트림은 InputStream을 상속받아 사용한다. 자바 API에서의 정의는 아래와 같다.
- 출처 : java API ( 글의 내용의 바탕은 API 기준으로 작성되었다.)
This abstract class is the superclass of all classes representing an input stream of bytes. Applications that need to define a subclass of InputStream must always provide a method that returns the next byte of input. ( 이 추상 클래스는 바이트의 입력 스트림을 나타내는 모든 클래스의 슈퍼 클래스입니다. InputStream의 하위 클래스를 정의해야 하는 응용 프로그램은 항상 다음 입력 바이트를 반환하는 메서드를 제공해야 합니다.)
자 이제 해당 클래스를 사용해보도록 하자.
- 선언 InputStream
package tInputStream;
import java.io.IOException;
import java.io.InputStream;
public class Main {
public static void main(String[] args) {
InputStream is = System.in;
}
}
선언 방법은 간단하다. 위의 코드처럼 InputStream의 객체에 System.in을 받아 콘솔에 입력받을 수 있는 is 객체를 만든다. 여기서 new InputStream() ; 이런식으로 선언하면 안 되나?라고 생각할 수 있지만 초기 API 정의에서도 볼 수 있듯이 InputStream은 추상클래스이기 때문에 new 연산자로의 생성은 불가하다.
- read() 메서드
InputStream은 read라는 메서드로 바이트 형식의 데이터를 받아들이게 된다.
read 메서드의 매개변수로는 바이트형 배열을 받게 된다. 또한 여기서 두 가지의 매개 값을 줄 수 있는데, 이는 해당 매개 변수의 의미는 바이트 배열의 시작 값(off)과 끝 값(len)을 나타낸다. 때문에 우리는 해당 데이터를 입력받을 바이트 배열과 총길이를 확인할 인트형 변수를 하나 선언해 줄 것이다. 이제 아래의 코드를 살펴보자.
package tInputStream;
import java.io.IOException;
import java.io.InputStream;
public class Main {
public static void main(String[] args) {
InputStream is = System.in;
// InputStream API 상에서 추상 클래스 이기 때문에
// new 연산자를 사용하려면 자식클래스를 받아야 한다.
// public abstract class InputStream
// extends Object
// implements Closeable
//
byte [] arr = new byte [100];
// 콘솔된 입력된 데이터를 100개의 바이트까지
// 읽을 수 있는 배열을 생성한다.
// loop의 반복 횟수를 줄여서 속도를 높여준다.
// 자신의 컴퓨터 환경에 맞게 알맞은 배열크기를
// 설정하는 것이 중요하다.
int checkByte = -1;
// 계속 입력받는 데이터가 있는지 확인할 변수
System.out.println("데이터를 입력해주세요 -> ");
try {
while((checkByte = is.read(arr)) != -1) {
// read 메서드는 더이상 읽을 데이터가 없을 경우
// -1을 리턴하게 된다.
// 때문에 -1을 리턴하기 전까지 반복하면 된다.
String temp = new String(arr, 0, checkByte);
System.out.println("read로 받은 데이터는 - > " + temp);
// 이후 String의 새로운 객체로 배열과 배열의 시작위치
// 현재 입력받은 데이터의 길이를 매개 값으로 주어 출력을 해보자.
System.out.println("[ctrl + z] 누르면 InputStream는 종료됩니다. ");
// ctrl + z 는 입력 콘솔창을 종료시키는 단축키다.
// 설정에 따라 조금 다를 수 있다.
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
System.out.println("\n자원을 닫습니다.");
is.close();
// 자원을 모두 사용한 후
// 자원을 이제 풀어주기 위해
// close를 호출해준다.
System.out.println("\n====프로그램 종료 완료====");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
사실 주석이 많아 코드가 복잡해 보일 수 있으나, 주석을 제외하면 간단하다. 여기서의 핵심코드는 while문의 내부라고 할 수 있다. 우선 while문의 조건으로 입력받은 데이터의 길이를 checkByte로 확인한다. 여기서 checkByte가 -1이 나온다면, 입력받은 데이터는 더 이상 존재하지 않는다는 의미이기 때문에 루프를 종료한다. -> ctrl + z를 누르면 finally 문으로 이동해 InputStream 을 닫아 줌으로써 프로그램이 종료된다.
다음은 InputStream 객체 is가 입력된 데이터를 계속해서 매개값으로 주어진 바이트배열에 담고 이 내용을 다시 스트링 객체에 담아준다. 여기서 sysout 출력문을 통해 String 객체에 담긴 데이터 즉 루프당 read로 읽은 바이트 데이터를 문자열의 형태로 확인을 할 수 있게 된다.
단 이와 같은 과정에서 IOException 발생할 수 있기 때문에, try / catch 문을 이용해 함 번 감싸주어 안전하게 프로그램이 동작하도록 유도할 수 있다.
프로그램을 한 번 실행해 보았으며, 결과는 아래와 같다.