[TIL] 2022년 9월 19일 월요일
3. 바이트기반의 보조스트림
3.1 FilterInputStream과 FilterOutputStream
- FilterInputStream과 FilterOutputStream은 각각 InputStream과 OutputStream의 자식 클래스이면서 보조스트림 클래스의 조상 클래스
- FilterInputStream/FilterOutputStream은 보조스트림으로 자체적으로 입출력을 수행할 수 없고 InputStream과 OutputStream이 필요함
- FilterInputStream/FilterOutputStream은 각각 InputStream과 OutputStream의 모든 메소드를 상속받을 수 있고 상속을 통해 원하는 작업을 수행하도록 오버라이딩해야 함
- FilterInputStream은 접근제한자가 protected로 인스턴스를 생성할 수 없고 상속을 통해 오버라이딩 해야함
3.2 BufferedInputStream과 BufferedOutputStream
- 버퍼란 임시메모리 공간으로 위 그림에서 키보드로 'LOVE'를 쓸 때 'L'을 누를 때 'L', 'O'를 누를 때 'O' 를 바로 프로그램에 보여주는 것이 아니라 버퍼에 'L', 'O', 'V', 'E'를 저장해두었다가 버퍼가 가득 차거나 개행문자가 나타나면 버퍼의 내용을 프로그램에 전송하는 것
- BufferedInputStream/BufferedOutputStream은 버퍼를 이용하여 스트림의 입출력 효율을 높히는 보조스트림
- 외부의 입력소스로부터 읽는 것보다 내부의 버퍼로부터 읽는 것이 빨라 효율이 올라감
- InputStream의 인스턴스를 입력소스로 함.
- int size를 통해 버퍼의 사이즈를 지정할 수 있고 크기를 지정하지 않으면 8192byte(8K)크기의 버퍼가 생김
- BufferedInputStream은 버퍼의 크기만큼 입력 소스에서 데이터를 읽어와 버퍼에 저장하는 작업을 반복함
- OutputStream을 출력 소스로 함.
- InputStream과 마찬가지로 int size로 버퍼의 사이즈를 정할 수 있고 지정하지 않으면 8192 byte크기의 버퍼가 생김
- BufferedOutputStream은 write()를 하면 출력이 버퍼에 저장하고 버퍼가 가득차면 버퍼의 모든 내용을 출력.
- 버퍼가 가득 찼을 때만 출력하기 때문에 버퍼에 데이터가 남은 채로 종료될 수 있음
- close()나 flush()를 호출하여 버퍼스트림에 저장된 모든 내용을 출력하게 해야 함
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class BufferedOutputStreamEx {
public static void main(String[] args) {
try{
FileOutputStream fos = new FileOutputStream("123.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos, 5);
for(int i='1'; i<='9'; i++)
bos.write(i);
fos.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
- 위 코드는 FileOutputStream으로 123.txt 파일을 만들고, 버퍼의 크기가 5인 BufferedOutputStream으로 1부터 9까지 출력하는 예제이지만 실제로 실행해보면 1부터 5까지만 저장이 됨 → BufferedOutputStream은 버퍼가 가득 찼을 때만 출력하기 때문에 1부터 5까지 write()했을 땐 버퍼가 가득차서 출력을 했지만 6에서 9까지 write()할 때는 버퍼가 가득 차지 않아 출력하지 못함
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class BufferedOutputStreamEx {
public static void main(String[] args) {
try{
FileOutputStream fos = new FileOutputStream("123.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos, 5);
for(int i='1'; i<='9'; i++)
bos.write(i);
fos.close();
bos.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
- 남은 6부터 9를 출력하기 위해 위와 같이 코드를 작성 → FileOutputStream의 인스턴스 fos가 close()에 의해 닫힌 뒤 BufferedOutputStream의 인스턴스 bos를 close()하면 오류가 발생함. 보조 스트림이 스트림에 의존적이라는 걸 확인
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class BufferedOutputStreamEx {
public static void main(String[] args) {
try{
FileOutputStream fos = new FileOutputStream("123.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos, 5);
for(int i='1'; i<='9'; i++)
bos.write(i);
bos.close();
fos.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
- BuffredOutputStream의 인스턴스 bos에 close()를 호출하여 버퍼에 저장된 내용을 출력하게 하고 FileOutputStream fos를 close()하니 에러가 발생하지 않고 원하던 대로 1부터 9까지 출력
3.4 SequenceInputStream
- 여러 개의 입력스트림을 하나의 스트림으로부터 데이터를 읽어오는 것처럼 처리할 수 있도록 도와줌
- 큰 파일을 여러 개의 작은 파일로 나누었다가 하나로 합치는 것 같은 작업을 할 때 사용
- FilterInputStream이 아니라 InputStream을 상속
3.5 PrintStream
- PrintStream은 print, println, printf를 오버로딩하여 데이터를 다양한 형태로 출력
- 문자기반 스트림과 동일한 역할로 JDK1.1부터 PrintWriter를 추가했으나 System.out이 PrintStream이므로 둘다 사용하게 됨
- 다양한 언어를 처리하는데 적합하므로 PrintWriter를 사용하는 것이 좋음