보조 스트림
다른 스트림과 연결이 되어 여러 가지 편리한 기능을 제공해주는 스트림을 말한다.
보조 스트림 자체적으로 입출력을 수행할 수 없기 때문에 입출력 소스와 바로 연결할 수 있는
InputStream, OutputStream, Reader, Writer 등에 연결해서 입출력을 수행한다.
그렇다면 보조 스트림의 기능은 무엇일까?
문자를 변환할 수 있고, 입출력 성능을 향상시킬 수 있으며 기본 타입 입출력 등의 기능을 제공한다.
보조 스트림 연결하는 방법은 아래와 같다.
보조스트림 변수 = new 보조스트림(연결스트림)
위의 사진과 같이 보조 스트림을 연속적으로 연결할 수 있다.
그리고 프로그램은 입력 스트림으로부터 직접 데이터를 읽지 않고 보조 스트림에서 제공하는 기능을
이용해서 데이터를 읽는다. 반대로 출력 스트림 또한 출력 스트림으로 직접 데이터를 보내지 않고
보조 스트림에서 제공하는 기능을 이용해서 데이터를 보낸다.
문자 변환 보조 스트림
OutputStreamWriter
바이트 기반 출력 스트림에 연결되어 문자 스트림인 Writer로 변환하는 보조 스트림
InputStreamReader
바이트 기반 입력 스트림에 연결되어 문자 입력 스트림인 Reader로 변환하는 보조 스트림
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
public class ReaderWriter {
public static void main(String[] args) throws IOException{
write("문자 변환 보조 스트림을 사용하기");
String data = read();
System.out.println(data);
}
public static void write(String str) throws IOException{
// FileOutputStream으로 바이트 스트림 쓰기
FileOutputStream fos = new FileOutputStream("c:/Temp/test1.txt");
// 바이트 스트림을 문자 변환 보조 스트림으로 연결하기
Writer writer = new OutputStreamWriter(fos);
// 문자열 단위로 출력
writer.write(str);
writer.flush();
writer.close();
}
// String data = read();에서 String으로 값을 받기 때문에 리턴값은 String
// FileInputStream 클래스를 사용하여 한 파일을 읽어서 그 내용을 문자열로 리턴한다.
public static String read() throws IOException {
FileInputStream fis = new FileInputStream("c:/Temp/test1.txt");
// 바이트 스트림을 문자 변환 보조 스트림으로 연결하기
Reader reader = new InputStreamReader(fis);
// 파일의 내용을 문자열 단위로 저장할 임시 저장소 변수 선언
char[] buffer = new char[100];
// 파일로부터 데이터를 읽을 때 조금 더 빠르게 읽도록 buffer를 사용
int readCharSize = reader.read(buffer);
reader.close();
// char[] buffer의 내용을 문자열로 만든다.
// 0부터 시작해서 지정한 크기만큼의 배열의 내용을 읽어 문자열로 바꿔라.
String data = new String(buffer, 0, readCharSize);
return data;
}
}
실행 결과는 아래의 사진과 같다.
성능 향상 보조 스트림
프로그램이 입출력 소스와 직접 작업하지 않고 중간에 메모리 버퍼와 작업함으로써 실행 성능을
향상시킬 수 있다.
여기서 버퍼라는 단어가 나오는데 버퍼란 데이터를 한 곳에서 다른 한 곳으로 전송하는 동안 일시적으로
그 데이터를 보관하는 메모리의 영역을 말한다. 아래의 사진을 참고하자.
BufferedOutputStream
바이트 기반 출력 스트림에 연결되어 버퍼를 제공해주는 보조 스트림
BufferedWriter
문자 기반 출력 스트림에 연결되어 버퍼를 제공해주는 보조 스트림
BufferedOutputStream과 BufferedWriter는 프로그램에서 전송한 데이터를 내부 버퍼에 쌓아두었다가
버퍼가 꽉 차면, 버퍼의 모든 데이터를 한꺼번에 보낸다.
BufferedInputStream
바이트 기반 입력 스트림에 연결되어 버퍼를 제공해주는 보조 스트림
BufferedReader
문자 기반 입력 스트림에 연결되어 버퍼를 제공해주는 보조 스트림
BufferedInputStream과 BufferedReader는 입력 소스로부터 자신의 내부 버퍼 크기만큼 데이터를
미리 읽고 버퍼에 저장해둔다.
package ex;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class Buffered {
public static void main(String[] args) throws Exception {
// 기본 스트림
// 현재 프로그램의 경로에 있는 "originalFile1.jpg"의 실제 위치를 가져온다.
String originalFilePath1 = Buffered.class.getResource("originalFile1.jpg").getPath();
// 복사할 경로를 가르키는 문자열
String targetFilePath1 ="c:/Temp/targetFile1.jpg";
// 일반 스트림을 이용해서 original의 파일 내용을 target 파일에 복사
// 실제 파일을 읽어오는 스트림(InpustStream)
FileInputStream fis = new FileInputStream(originalFilePath1);
// 파일을 저장할 스트림(OutputStream)
FileOutputStream fos = new FileOutputStream(targetFilePath1);
// 버퍼 보조 스트림
// 버퍼 스트림을 이용해서 original의 파일 내용을 target 파일에 복사
String originalFilePath2 = Buffered.class.getResource("originalFile2.jpg").getPath();
String targetFilePath2 = "c:/Temp/targetFile2.jpg";
FileInputStream fis2 = new FileInputStream(originalFilePath2);
FileOutputStream fos2 = new FileOutputStream(targetFilePath2);
BufferedInputStream bis = new BufferedInputStream(fis2);
BufferedOutputStream bos = new BufferedOutputStream(fos2);
// 실제 copy를 진행하는 부분(= NonBuffered)
long nonBufferTime = copy(fis, fos);
System.out.println("버퍼를 사용하지 않았을 때 :\t" + nonBufferTime + "ns");
// 실제 파일 copy를 진행하는 부분(= Buffered)
long bufferTime = copy(bis, bos);
System.out.println("버퍼를 사용했을 때 :\t" + bufferTime + "ns");
fis.close();
fos.close();
bis.close();
bos.close();
}
static int data = -1; // 입력 스트림으로부터 1바이트의 데이터를 읽을 때 그 데이터를 저장할 변수
public static long copy(InputStream is, OutputStream os) throws Exception{
long start = System.nanoTime(); // 시작 시간을 저장하는 변수
// 입력 스트림이 출력 스트림으로 복사하는 루틴
// 입력 스트림의 크기를 모르므로 무한 루프
while(true) {
data = is.read(); // 입력 스트림으로부터 1바이트 읽어오기
if(data == -1) break; // 입력 스트림으로부터 읽은 값이 -1이면 파일의 끝
os.write(data); // 실제 데이터를 출력 스트림에 저장
}
os.flush();
long end = System.nanoTime();
long diff = (end - start); // 두 시간의 차이
return diff;
}
}
originalFile1과 originalFile2의 위치는 아래의 사진과 같다.
코드를 실행시키면 아래의 사진과 같이 사진들이 복사되는 것을 확인할 수 있다.
또한 버퍼를 사용하지 않았을 때 걸린 시간보다 버퍼를 사용했을 때 걸린 시간이 훨씬 짧은 것을 확인할 수 있다.
'국비 지원 > JAVA' 카테고리의 다른 글
[JAVA] 문자 기반 입출력 스트림 (2) (1) | 2023.06.05 |
---|---|
[JAVA] 바이트 기반 입출력 스트림 (1) (0) | 2023.06.04 |
[JAVA] ArrayList와 제네릭(Generic) (0) | 2023.05.28 |
[JAVA] 예외 처리 (0) | 2023.05.21 |
[JAVA] final과 상수(static final) (0) | 2023.05.21 |