3.1 FilterInputStream 과 FilterOutputStream

InputStream/OutputStream 의 자손이면서 모든 보조스트림의 조상 이다. 보조스트림은 자체적으로 입출력을 수행할 수 없기 때문에 기반스트림을 필요로 한다.

모든 메서드는 단순히 기반스트림의 메서드를 그대로 호출할 뿐이다. 상속을 통해 원하는 작업을 수행하도록 읽고 쓰는 메서드를 오버라이딩해야 한다.

3.2 BufferedInputStream 과 BufferedOutputStream

스트림의 입출력 효율을 높이기 위해 버퍼를 사용하는 보조스트림이다. 한 바이트씩 입출력하는 것보다는 버퍼(바이트배열)를 이용해서 한 번에 여러 바이트를 입출력하는 것이 빠르기 때문에 대부분의 입출력 작업에 사용된다.

BufferedInputStream 의 버퍼크기는 입력소스로부터 한 번에 가져올 수 있는 데이터의 크기로 지정하면 좋다. 보통 입력소스가 파일인 경우 4096 정도의 크기로 하는 것이 보통이며, 버퍼의 크기를 변경해가면서 테스트하면 최적의 버퍼크기를 알아낼 수 있다.

BufferedInputStream 은 입력소스로부터 버퍼 크기만큼의 데이터를 읽어다 자신의 내부 버퍼에 저장한다. 이제 프로그램에서는 BufferedInputStream 의 버퍼에 저장된 데이터를 읽으면 되는 것이다. 외부의 입력소스로부터 읽는 것보다 내부의 버퍼로부터 읽는 것이 훨씬 빠르기 때문에 작업 효율이 높아진다.

프로그램에서 버퍼에 저장된 모든 데이터를 다 읽고 그 다음 데이터를 읽기 위해 read 메서드가 호출되면, BufferedInputStream 은 입력소스로부터 다시 버퍼크기 만큼의 데이터를 읽어다 버퍼에 저장해 놓는다. 이와 같은 작업이 계속해서 반복된다.

BufferedOutputStream 역시 버퍼를 이용해서 출력소스와 작업을 하게 되는데, 입력소스로부터 데이터를 읽을 때와는 반대로, 프로그램에서 write 메서드를 이용한 출력이 BufferedOutputStream 의 버퍼에 저장된다. 버퍼가 가득 차면, 그 때 버퍼의 모든 내용을 출력 소스에 출력한다. 그리고는 버퍼를 비우고 다시 프로그램으로부터의 출력을 저장할 준비를 한다.

버퍼가 가득 찼을 때만 출력소스에 출력을 하기 때문에 마지막 출력 부분이 출력 소스에 쓰이지 못하고 BufferedOutputStream 의 버퍼에 남아있는 채로 프로그램이 종료될 수 있다는 점을 주의해야 한다.

그래서 프로그램에서 모든 출력작업을 마친 후 BufferedOutputStream 에 close() 나 flush() 를 호출해서 마지막에 버퍼에 있는 모든 내용이 출력소스에 출력되도록 해야 한다.

보조스트림의 close() 에 기반스트림의 close() 도 포함되어 있으므로 보조스트림을 닫아주어야 한다.