Java IO에서 InputStream, OutputStream, Reader, Writer
Java에서 IO(Input/Output)라는 것을 하게 되면
InputStream, OutputStream, Reader, Writer 를 사용하게 되는데요.
오늘은 이들에 대해서 기본적인 것들을 정리해보려고 합니다.
1. Stream or Reader, Writer?
자바 IO는 입출력에 관해, 크게 두가지로 나눌 수 있습니다.
하나는, 바이트 단위로 입출력을 하는 Stream이구요, 여기엔 InputStream과 OutputStream이 있습니다.
다른 하나는, 2바이트인 문자단위 입출력을 하는 Reader, Writer입니다.
InputStream과 Reader가 입력을, OutputStream과 Writer가 출력을 담당하므로,
두 개씩 묶어서 보도록 하겠습니다.
2. InputStream, Reader
먼저 InputStream 소스를 보겠습니다.
객체를 생성할수 없는 추상클래스인데요,
이들을 상속받은 FileInputStream같은 클래스들이 객체화되서,
어떤 역할을 할 것이라는 것을 추측해 볼 수 있습니다.
이번에는, InputStream은 메소드들을 쭈욱 한번 보겠습니다.
역시 읽어들이는 것이 주기능이라고 생각되므로, Read()가 눈에 띄는데요.
Read는 밑에서 소스를 열어서 보도록 하구요,
available이 스트림으로부터 읽을수 있는 바이트수를 반환해주고,
close메소드는 스트림과 관련된 자원들을 닫아주는 메소드이군요.
이런 메소드가 있는 걸 보면, 다 사용하고 close()를 써줘얄듯 하네요.
아쉽지만, 어떤 라이브러리처럼 자동으로 다 쓰고 반환해주거나 하지는 않겠네요~.
(https://docs.oracle.com/javase/7/docs/api/)
Read메소드의 소스를 보니, 아래와 같습니다.
byteOffset으로부터 시작해서,
스트림을 byteArray에 읽어들이는데,
byteCount까지 읽어들이는 군요.
저장은 byteArray인 buffer에 한다고 하네요.
그리고, 반환값은 읽어들인 바이트 수인데, 스트림의 끝에 도달하면 -1을 반환한다고 되어 있습니다.
어떻게 얼마나 어디에 읽는지를 알려주는 군요.
이번에는 Reader의 메소드들을 보도록 하겠습니다.
역시나 메인은 Read메소드이고, close로 닫아야 할듯 합니다.
읽어들일 때 저장하는 곳이, byteArray가 아니고, charArray라는 점이 큰 차이라고 할 수 있겠네요.
3. OutputStream, Writer
잠깐 삼천포로 빠져서, Flushable 인터페이스의 소스를 보겠습니다.
flush()를 구현해야 하는 군요.
버퍼에 들어간 데이터를 다 출력해서 오브젝트를 날려버린다고 주석에 달려있는데요.
음... 일단, 출력이라는 과정에 완충지인 버퍼를 사용하는데,
flush() 라는 메소드를 통해서, 버퍼에 남은 데이터를 다 출력해야되나 봅니다.
궁금하니 OutputStream의 메소드들도 보겠습니다.
위에서 봤던, flush소스와 연결시켜보면,
출력하는 Write는 버퍼를 완충지로 사용하는데,
출력을 최종적으로 마무리를 할려면,
flush()를 꼭 구현해서, 데이터를 완전히 다 출력한다음
close()로 객체를 버릴수 있다는 시나리옵니다.
그러면, write소스도 한번 보시죠.
offset에서 시작하여, byteArray버퍼에서 Count바이트 만큼을 출력한다고 되어있네요.
역시나 Buffer의 존재를 확인할 수 있습니다.
OutputStream이 Buffer에 데이터를 채워넣고 있다가 출력하는 거군요.
그냥 바로 출력하지 않는다는 점을 생각해 두어야 하네요.
Writer도 물론 추측이 가능할 것 같습니다.
하지만, 메소드 살짝 보고 가시죠.
역시나, 출력하는 단위가 byteArray가 아니라 charArray라는 것이 큰 차이라고 할 수 있겠습니다.
flush나 close메소드 역시 존재합니다.
4. 실제 코드에서의 사용
InputStream, OutputStream. Reader, Writer 를 어떻게 사용하게 될까요?
이들은 위에서 말씀드린 것처럼, 추상클래스입니다.
객체화 시킬수가 없다는 거죠.
위 4개의 클래스들을 상속받은 FileInputStream같은 클래스를 객체화 시켜서 사용해야 합니다.
사용목적에 따라서 적절한 메소드를 가지고 있는 클래스를 사용하게 되는데, 이때 데코레이터 패턴이라는
디자인 패턴을 사용하게 됩니다.
실제로 적용하고, 응용하는 코드는 다음글에서 정리해보도록 하겠습니다~.