스트림(stream)
스트림(stream)이란 실제의 입력이나 출력이 표현된 데이터의 이상화된 흐름을 말한다.
- 보통 시스템은 여러가지 입출력 장치를 가지고 있고 장치에 따라 입출력 부분을 다르게 구현하면 호환성이 떨어지기 마련이다.
이런 입출력 장치를 다루기 위한 각각의 방법이 있다면 입출력을 사용할때 어떤 데이터 형식을 사용할것인지가 이미 정해져있다는 것을 의미한다. 예를 들어 키보드로 입출력을 받는데 사용되는 입출력 방식, 데이터 형식과 네트워크를 통해 입출력되는 입출력 방식, 데이터 형식이 다르다면 시스템의 다양한 입출력 을 사용하기 위해서는 각각의 입출력 방식, 데이터 형식을 사용자가 이해하고 있어야 사용할 수 있었고 이런 방식은 프로그래밍을 힘들게 한다.
- 이를 해결하기 위해 자바에서는 파일이나 콘솔의 입출력을 직접 다루지 않고 모든 입출력의 기반이 될수 있는 기술인 스트림(stream)이라는 흐름을 통해 다룬다.
스트림(stream)이란 구체적 데이터 형식이 정해지지 않은 데이터의 입출력 흐름을 의미하는 것으로 입출력 장치와 무관하고 일관성 있는 프로그램의 구현을 위한 일종의 가상통로(데이터를 전송하는 소프트웨어 모듈)를 의미한다.
스트림은 표준적인 입출력 형식을 제공하고, 구체적인 장치에 대한 입출력 기능들은 스트림 구조를 확장해서 비어 있는 각 메서드들의 기능을 구현해 사용할수 있도록 제공한다.이를 통해 시스템의 모든 입출력을 스트림을 기반으로 설계해서 통일성을 유지할수 있고 프로그래머는기본 스트림의 형식만 이해하고 있다면 얼마든지 다양한 장치의 입출력을 사용할수 있게 된다.
- 스트림은 운영체제에 의해 생성되는 가상통로를 의미하며, 중간 매개자 역할을 합니다.
입력 스트림은 입력 장치를 제어하여 입력을 받고 응용프로그램에게 전달하는 것처럼 보이지만 실제로 스트림이 입출력 장치를 제어하는 것은 아니며 스트림은 내부적으로 운영체제의 API인 시스템 콜을 호출하고 실제로는 입출력 장치를 제어하는 역할을 운영체제가 담당한다.
자바의 스트림
자바에서는 스트림은 응용프로그램과 입출력 장치를 연결하는 소프트웨어 모듈을 말한다. 스트림은 연속적인 데이터의 흐름을 물에 비유해서 붙여진 이름으로 물이 한쪽 방향으로 흐르는 것과 같이 스트림은 단방향 통신만 가능하기 때문에 하나의 스트림으로 입출력을 동시에 처리할 수 없다. 그래서 입력과 출력을 통시에 처리하기 위한 입력스트름과 출력을 위한 출력스트림 모두 2개의 스트림이 필요하다.
- 입력 스트림 : 입력 장치로부터 자바 프로그램으로 데이터를 전달
- 출력 스트림 : 출력 장치로 데이터 출력
자바에서는 입출력을 위해 java.io 패키지를 통해서 많은 종류의 입출력 관련 클래스들을 제공하며, 입출력을 처리할 수 있는 표준화된 방법을 제공함으로써 입출력의 대상이 달라져도 동일한 방법르호 입출력이 가능하기 때문에 프로그래밍 하기 편안하다.
스트림의 특징
스트림은 단방향이다.
- 데이터의 흐름을 나타내는 스트림은 입력과 출력을 동시에 처리할 수 없어 사용 목적에 따라 입력 스트림과 출력 스트림으로 구분되며 입출력을 동시에 수행하기 위해서는 2개의 스트림이 필요하다.
입출력 스트림의 기본 전송 단위에 따라 구분된다.
- 바이트/ 문자 스트림 : 스트림은 전송단위에 따라 바이트 스트림과 문자 스트림으로 구분된다.
스트림은 선입선출 구조이다.
- 스트림의 데이터는 순차적으로 흘러가며 순차적 접근만 허용, 즉 데이터의 순서가 바뀌지 않는다.
- 스트림은 먼저 보낸 데이터를 먼저 받게 되어 있으며 중간에 건너뜀 없이 연속적으로 데이터를 주고 받는다.
- 큐(Queue)와 같은 FIFO구조
스트림은 연결될 수 있다.
아래 코드는 표준 입력 스트림인 System.in과 InpurSreamReader 스트림 객체를 연결하는 예제이다.
InputStreamReader rd = new InputStreamReader(System.in);
int c = rd.read(); // 키보드에서 문자 읽음
- 표준 입력 스트림인 System.in은 시스템에서 설정된 입력 스트림을 따르겠다는 뜻으로 일반적으로 키보드와 연결되어 있고 Host와 환경에 따라 Stream, Redaer, File 와 같은 다른 입력 소스가 될 수도 있다.
- 두 스트림을 연결하여 바이트 스트림인 System.in은 키보드로부터 사용자의 키를 입력 받아서 바이트 스트림을 내보내고, InputStreamReader은 바이트 스트림을 받아서 문자로 변환하여 자바 응용 프로그램에 전달한다.
바이트 스트림
바이트 스트림은 바이트 단위의 바이너리 값를 입출력 하는 스트림을 말한다.
바이트 스트림은 java.io 패키지의 두 개의 추상 클래스 InputStream과 OutputStream를 통해 계층을 형성하고 있다.
- 바이트 스트림을 다루는 모든 클래스의 슈퍼 클래스
- 클래스 이름이 공통적으로 Stream으로 끝나는 클래스
바이트스트림은 데이터를 전송하며 입출력 대상에 따라 다음과 같은 입출력 스트림이 있다. 어떠한 대상에 대해서 작업을 할 것인지 그리고 입력을 할 것인지 출력을 할것인지에 따라 스트림을 선택해서 사용하면 된다.
바이트 기반 스트림
InputStream 클래스는 입력 소스에서 바이트 및 배이트 배열과 같은 데이터를 읽는 데 사용된다.
- 상속된 모든 입력 스트림에 대한 프로그래밍 인터페이스를 정의하는 추상 클래스이다.
- 입력 스트림 생성 시 자동으로 열린다.
OutputStream 클래스는 입력 소스에서 바이트 및 배이트 배열과 같은 데이터를 쓰는 데 사용된다.
- OutputStream의 각 하위 클래스는 다른 목적을 위해 만들어 졌다.
- 입력 스트림과 마찬가지로 생성 시 자동으로 열린다.
바이트 기반 스트림은 모두 InputStream/OutputStream의 자손들이며, 각각 읽고 쓰는데 필요한 추상 메서드를 자신에 맞게 구현해 놓았다.
- read()와 write()는 추상 메서드로 입출력의 대상에 따라 읽고 쓰는 방법이 다르기 때문에 상황에 알맞게 구현하라는 의미이다.
입력 스트림 | 출력 스트림 | 입출력 대상 |
FileInputStream | FileOutputStream | 파일 |
ByteArrayInputStream | ByteArrayOutputStream | 메모리 |
PipedInputStream | PipedOutputStream | 프로세스 |
AudioInputStream | AudioOutputStream | 오디오 장치 |
InputStream과 OutputStream
InputStream과 OutputStream 은 모든 바이트 기반의 스트림이 조상이며 다음과 같은 메서드가 선언되어 있다.
read() 메서드는 입력 스트림에서 더 이상 읽어들일 바이트가 없다면, -1을 반환해야 한다.
- 만약 반환타입이 byte 라면, 0~255까지의 바이트 정보는 표현할 수 있지만 -1은 표현할 수 없게 된다.
따라서 read(0 메서드는 반환 타입을 int형으로 선언하고 있다.
모든 작업을 마치고 난 후 에는 close()를 호출해서 스트림을 반드시 닫아주어야 한다.
- JVM이 자동적으로 닫아 주지만 작업을 마친후 닫아 주는것이 바람직하다.
- ByteArrayInputStream과 같이 메모리를 사용하는 스트림이나 System.in, System.Out과 같은 표준 입출력 스트림은 닫지 않아도 된다.
flush()는 버퍼가 있는출력스트림의 경우에만 의미가 있기 때문에 OutputStream의 flush() 메서드를 아무런 일도 하지 않는다.
FileInputStream과 FileOutputStream
FileInputStream과 FileOutputStream은 파일에 입출력 하기 위한 스트림으로 실제 프로그래밍에서 많이 사용되는 스트림 중의 하나이다.
FIleOutputStream(File, boolean append) | 파일의 이름을 String이 아닌 File인스턴스로 지정해주어야 하는 점을 제외하고 FileOutputStream(String name, boolean append)와 같다. |
바이트 보조 스트림
보조스트림은 스트림의 기능을 향상시키거나 새로운 기능을 추가하기 위한 스트림으로 실제 데이터를 주고받는 스트림이 아니기 때문에 독립적으로 데이터의 입출력을 수행할 수 없다.
- 스트림을 생성한 다음에 이를 이용해서 보조스트림을 생성해야 한다.
입력 스트림 | 출력 스트림 | 설명 |
FilterInputStream | FilterOutputStream | 필터를 이용한 입출력 |
BufferedInputStream | BufferedOutputStream | 버퍼를 이용한 입출력 |
DataInputStream | DataOutputStream | 입출력 스트림으로부터 자바의 기본 타입으로 데이터를 읽어올 수 있게 함. |
ObjectInputStream | ObjectOutputStream | 데이터를 객체 단위로 읽거나, 읽어 들인 객체를 역직렬화시킴. |
SequenceInputStream | X | 두 개의 입력 스트림을 논리적으로 연결함. |
PushbackInputStream | X | 다른 입력 스트림에 버퍼를 이용하여 push back이나 unread와 같은 기능을 추가함. |
X | PrintStream | 다른 출력 스트림에 버퍼를 이용하여 다양한 데이터를 출력하기 위한 기능을 추가함. |
FilterInputStream과 FilterOutputStream
FilterInputStream과 FilterOutputStream은 InputStream과 OutputStream의 자손이면서 모든 보조 스트림의 조상이다.
- FilterInputStream과 FilterOutputStream의 생성자
protected FilterInputStream(InputStream in) | |
public FilterOutputStream(OutputStream out) |
FilterInputStream과 FilterOutputStream같은 보조 스트림의 모든 메서드는 단순히 기반 스트림의 메서드를 그대로 호출할 뿐이다. FilterInputStream과 FilterOutputStream 자체로는 아무일도 하지 않으며 상속을 통해 원하는 작업을 수행하도록 읽고 쓰는 메서드를 오버라이딩 해야 한다.
- FilterInputStream(InputStream in)의 접근 제어자는 protected이기 때문에 인스턴스를 생성해서 사용할 수 없고 상속을 통해서 오버라이딩되어야 한다.
BufferedInputStream과 BufferedOutputStream
바이트 단위의 바이너리 데이터를 처리하는 스트림의 입출력 효율을 높이기 위해 버퍼 (byte[])를 사용하는 보조 스트림이다.
- 보조스트림을 닫으면 기반스트림도 닫힌다.
- 버퍼를 사용하여 입출력 효율을 높이는 스트림을 말한다.
버퍼(Buffer)?
버퍼란 데이터를 한 곳에서 다른 한 곳으로 전송하는 동안 일시적으로 그 데이터를 보관하는 메모리의 영역을 말한다.
- 버퍼링 (buffering) 버퍼를 활용하는 방법 또는 버퍼를 채우는 과정을 말한다.
동시에 버퍼는 입력받은 값은 버퍼에 저장해두었다가 버퍼가 가득차거나 개행 문자가 나타나면 버퍼의 내용을 한 번에 전송하게 된다
그렇다면 버퍼를 왜 사용하는 걸까?
입출력을 수행하는데에 있어서 속도차이를 극복하기 위해 사용하는 임시 저장 공간인 버퍼를 사용한다.
예를 들어 입력 장치는 1초당 100개의 데이터를 전송할 수 있고, 출력 장치는 1초당 10개의 데이터를 전송받을 수 있을 때 버퍼가 없다면 입역 장치의 속도를 출력 장치의 속도에 맞춰 입력 장치의 효율이 크게 떨어진다.
- 입력 장치의 속도를 출력 장치의 속도에 맞출 경우 1초에 100개의 데이터를 전송할 수 있는 입력 장치가 10개만 전송하게 되는 것어 입력 장치의 효율이 크게 떨어진다.
- 입력 장치의 효율을 떨어트리지 않기 위해 입력장치에서 버퍼로 데이터를 빠르게 보낸 뒤, 버퍼에 저장된 데이터를 출력장치 속도에 맞춰 사용하게 된다.
입출력의 데이터 전송 시 작업 횟수를 줄여 부하를 방지하기 위해 버퍼를 사용한다.
- 만약 버터가 없다면 데이터를 보낼 때 입력 장치에서 데이터를 바로 출력 장치에 보내게 되면 자바에서 운영체제의 API 호출 횟수가 늘어 부하가 걸리게 된다.
- 버퍼를 사용한다면 입력 장치에서 들어오는 값을 보퍼에 보관하고 버퍼에 충분한 크기의 데이터가 쌓인다면 출력 장치로 데이터를 전송함으로 써 작업 횟수를 줄여 장치의 부하를 낮춰준다.
이처럼 입출력 장치의 속도의 차이로인해 일을 쉬는 것을 방지고 입출력 장치의 동작 횟수를 줄임으로 효율을 높여 입출력 실행 속도가 떨어지지 않고 더 빠르고 안정적인 퍼포먼스를 낼 수 있게 해준다.
하지만 입력 작업에 버퍼를 쓰는 것이 반드시 좋은 것은 아니다. 빠른 반응이 요구되는 게임 등 프로램에선 버퍼를 사용하지 않는 것이 바람직하다.
BufferedInputStream
버퍼크기는 입력소스로부터 한 번에 가져올 수 있는 데이터의 크기로 지정하면 좋다.
- 보통 입력소스가 파일인 경우 4096 정도의 크기로 하는 것이 보통이다
- 작게는 1024부터 버퍼의 크기를 변경해가면서 테스트하면 최적의 버퍼 크기를 알아낼 수 있다.
read() 메서드를 호출하면, BufferedInputStream은 입력 소스로 부터 버퍼 크기만큼의 데이터를 읽어다 자신의 내부 버퍼에 저장한다.
- 예를 들어 2048의 크기로 BufferedInputStream의 인스턴스를 생성하고 read() 메서드를 호출하게 되면,
입력소스로부터 2048 byte 만큼 읽어와서 내부 배열에 저장하고, 2048 byte 중 1 byte만을 반환하게 된다. - read() 메서드로 내부 버퍼의 내용을 다 읽게 될 때 까지 입력소스에 추가적으로 접근하지 않게되고, 내부 버퍼의 내용을 다 읽으면 다시 입력소스에 접근해서 생성시 지정한 버퍼의 크기만큼 데이터를 읽어온다
- 외부의 입력소스를 읽는 것보다 내부의 버퍼로 부터 읽는 것이 빠르기 때문에 작업 효율이 높아진다.
BufferedOutputStream

BufferedOutputStream 역시 버퍼를 이용해서 출력소스와 작업을 하게 되는데, 입력소스로부터 데이터를 읽을 때와는 반대로, 프로그램에서 write메서드를 이용한 출력이 바로 전송하지 않고 BufferedOutputStream의 버퍼에 저장된다. 내부 버퍼에 데이터를 쌓아두었다가 버퍼가 가득차면 , 그 때 버퍼의 모든 내용을 출력소스에 출력한다. 그리고 버퍼를 비우고 다시 프로그램으로부터 출력을 저장할 준비를 한다.
- 버퍼가 가득 차면, 그 때 버퍼의 모든 내용을 출력 소스에 출력한다.
버퍼가 가득 찼을때만 출력소스에 출력을 하기 때문에, 마지막 출력 부분이 출력소스에 쓰여지지 못하고 버퍼에 남아있는 채로 프로그램이 종료될 수 있다는 점을 주의해야 한다.
- 따라서 프로그램에서 모든 출력 작업을 마친 후 BufferedOutputStream에 close()나 flush()를 호출해서 마지막에 버퍼에 있는 모든 내용이 출력소스에 출력되도록 해야 한다.
class Main {
public static void main(String[] args) {
try {
FileOutputStream fos = new FileOutputStream("test.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos, 10);
for (int i = '1'; i <= '9'; i++) {
bos.write(i);
}
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
1부터 9까지 출력하는 예제인데 test.txt에 아무것도 출력되지 않았다. 버퍼에 남아있는 데이터가 출력되지 못한 상태로 프로그램이 종료되었기 때문이다.
fos.close()로 스트림을 닫았지만 이런 방식은 버퍼에 있는 내용을 출력해 주지 못한다. BufferedOutputStream의 close()를 호출해줘야 버퍼에 남아있던 모든 내용이 출력된다.
- 기반 스트림인 FileOutputStream의 close()는 flush()를 호출한 다음 기반 스트림의 close()를 호출도록 되어있기 때문에 그대로 상속받는 보조스트림의 close()를 호출하기만 해도 기반스트림의 close()를 하지 않아도 된다.
DataInputStream과 DataOutputStream
DataInputStream은 DataInput인터페이스를, DataOutputStream는 DataOuput인터페이스를 각각 구현하여 데이터를 읽고 쓰는데 있어서, 8가지 가본 자료형의 단위로 읽고 쓸 수 있다는 장점이 있다.
- 기본형 단위로 읽고 쓰는 보조스트림
DataOutputStream은 각 기본 자료형 값을 16진수로 표현하여 저장한다.(int의 경우 4byte의 16진수)
- 각 자료형의 크기가 다르므로 출력할 때와 입력할 때 순서에 주의
반면 DataInputStream은 데이터를 읽어올 때 , 아무런 변환이나 자릿수를 셀 필요 없이 단순히 읽어 올 데이터의 타입에 맞는 메서드를 사용하기만 하면 된다.
- 여러 자료형으로 출력한 경우 , 읽을 때 반드시 쓰인 순서에 따라 읽어야 한다.
SequenceInputStream
SequenceInputStream은 여러개의 입력스트림을 연속적으로 연결해서 하나의 스트림처럼 다룰 수 있게 해준다.
큰 파일을 여러 개의 작은 파일로 나누었다가 하나의 파일로 합치는 것과 같은 작업을 수행할 때 사용하면 좋다.
- 다른 보조 스트림과 달리 InputSteam을 상속 받아 구현하였다.
Vector에 연결할 입력스트림들을 저장한 다음 Vector의 Enumeration elements()를 호출해 매개변수로 사용한다.
files.add(new FileInputStream("test.txt"));
files.add(new FileInputStream("test1.txt"));
SequenceInputStream in = new SequenceInputStream(files.elements());
PrintStream
PrintStream은 데이터를 기반스트림에 다양한 형태의 문자로 출력할 수 있는 print, prntln,printf와 같은 메서드를 오버로딩하여 제공하는 보조스트림이다.
- 문사 기반 스트림의 역할을 하므로 PrintStream보다 향상된 PrintWriter를 사용할 것을 권장한다.
- 자주 사용하던System.out과 System.err이 PrintStream이다.
문자 스트림
문자 스트림은 문자(char, 2 바이트 유니코드) 를 입출력 하는 스트림을 말한다.
- 문자로 표현되지 않는 데이터는 다루지 못한다.
- 이미지, 동영상과 같은 바이너리 데이터는 입출력 할 수 없다.
가장 오래된 버전의 java에서는 문자 스트림이 포함되어 있지 않아 자바에서 모든 입출력은 바이트 단위였다.
- char형이 1byte인 C언어와 달리 자바는 char형이 2byte이기 때문에 바이트기반의 스트림으로 문자를 처리하는데 이려움이 있었고 이 점을 보완하기 위해서 문자 기반의 스트림이 제공되었다.
문자 스트림은 java.io 패키지의 두 개의 추상 클래스 Reader과 Writer를 통해 계층을 형성하고 있다.
- 문자 스트림을 다루는 모든 클래스의 슈퍼 클래스
- 클래스 이름이 공통적으로 Reader/Writer으로 끝나는 클래스
바이트스트림과 만찬가지로 문자스트림은 데이터를 전송하며 입출력 대상에 따라 다음과 같은 입출력 스트림이 있다. 어떠한 대상에 대해서 작업을 할 것인지 그리고 입력을 할 것인지 출력을 할것인지에 따라 스트림을 선택해서 사용하면 된다.
문자 기반 스트림
InputStream/OutputStream이 바이트 기반 스트림의 조상인것과 마찬가지로 문자 기반 스트림은 Reader와 Writer의 자손들이며, 각각 읽고 쓰는데 필요한 추상 메서드를 자신에 맞게 구현해 놓았다.
문자 입출력 스트림 | 입출력 대상 | |
FileReader | FileWriter | 파일 |
CharArrayReader | CharArrayWriter | 메모리 |
PipedReader | PipedReader | 프로세스 |
StringReader | StringWriter | 문자열 |
Reader와 Writer
byte배열 대신 char배열을 사용한다는 것 외에는 InputStream/OutputStream의 메서드와 다르지 않다.
문자 기반 스트림인 Reader와 Writer 그리고 자손들은 여러 종류의 인코딩과 자바에서 사용하는 유니코드(UTF - 16)간의 변환을 자동적으로 처리해준다.
- Reader : 특정 인코딩을 읽어 유니코드로 변환
- Writer : 유니코드를 특정 인코딩으로 변환하여 저장한다.
FileReader와 FileWriter
FileReader와 FileWriter은 파일로부터 텍스트 데이터를 읽고, 파일에 쓰는데 사용된다.
- FileInputStream과 FileOutputStream과 사용법이 다르지 않다.
PipedReader와 PipedReader
PipedReader와 PipedReader은 쓰레드 간에 데이터를 주고 받을 때 사용된다.
- 입력과 출력스트림을 하나의 스트림으로 연결(conncat)해서데이터를 주고받는다는 특징이 있다.
- 쓰레드를 생성한 다음에 어느 한쪽 쓰레드에서 concat()를 호출해서 입력스트림과 출력스트림을 연결한다.
- 어느 한쪽 스트림만 닫아도 나머지 스트림은 자동으로 닫힌다.
class Main {
public static void main(String[] args) {
InputThread inThread = new InputThread("InputThread"); // InputThread 쓰레드 생성
OutputThread outThread = new OutputThread("OutputThread");// OutputThread 쓰레드 생성
// PipedReader와 PipedReader스트림을 연결
inThread.connect(outThread.getOutput());
outThread.start();
inThread.start();
}
}
class OutputThread extends Thread {
PipedWriter output = new PipedWriter(); // PipedWriter 스트림 생성
OutputThread(String name) {super(name);} // 생성자로 쓰레드 이름 지정
public void run() {
try {
String msg = "문자";
System.out.println(getName() + " Sent : " + msg);
// PipedWriter을 통해 msg의 값을 출력 소스에 쓴다.
output.write(msg);
output.close();
} catch (IOException e) {}
}
// 쓰레드에 생성된 PipedWriter 스트림을 반환한다.
public PipedWriter getOutput() {return output;}
// PipedReader을 매개변수로 받아 PipedWriter의 메서드 connect를 통해 연견한다.
public void connect(PipedReader input) {
try {
output.connect(input);
} catch (IOException e) {}
}
}
class InputThread extends Thread {
PipedReader input = new PipedReader(); // PipedReader 스트림 생성
StringWriter sw = new StringWriter(); // StringWriter 스트림 생성
InputThread(String name) {super(name);} // public Thread(String name) {this(null, null, name, 0);} 생성자로 쓰레드 이름 지정
public void run() {
try {
int data = 0;
// 입력 소스(PipedReader)로부터 하나의 문자 읽어 data에 저장, -1이 아니라면 반복
while ((data = input.read()) != -1) {
// StringWriter을 통해 data의 값을 출력 소스에 쓴다.
sw.write(data);
}
// 반복이 끝나면 StringWriter의 메서드 toString()을 통해 StringBuffer에 저장된 문자열을 반환한다.
System.out.println(getName() + " recived : " + sw.toString());
} catch (IOException e) {}
}
// 쓰레드에 생성된 PipedReader 스트림을 반환한다.
public PipedReader getInput() {return input;}
// PipedWriter을 매개변수로 받아 PipedReader의 메서드 connect를 통해 연견한다.
public void connect(PipedWriter output) {
try {
input.connect(output);
} catch (IOException e) {}
}
}
StringReader와 StringWriter
StringReader와 StringWriter는 CharArrayReader, CharArrayWriter와 같이 입출력 대상이 메모리인 스트림이다.
- StringReader는 문자열로부터 읽어 들이기 위한 클래스고, StringWriter는 자신의 내부 저장 공간에 출력된 내용을 문자열로 반환 할 수 있는 기능을 가진 클래스다.
생성자 | 설명 | |
StringReader(String s) | String s로 부터 읽어 들이는 StringReader 객체를 생성한다. | |
StringWriter() | 내부 저장 공간이 있는 StringWriter 객체를 생성한다. |
- StringWriter에 출력되는 데이터는 내부의 StringBuffer에 저장되고 StringWriter의 메서드를 통해 데이터를 얻을 수 있다.
- StringWriter는 내부적으로 StringBuffer를 가지고 있어 출력하는 내용이 저장된다.
메서드 | 설명 | |
StringBuffer getBuffer() | StringWriter에 출력한 데이터가 저종된 StringBuffer를 반환한다. | |
String toString | StringWriter에 출력된 (StringBuffer에 저장된) 문자열을 반환한다. |
문자 보조 스트림
문자 보조 스트림도 마찬가지로 보조스트림은 스트림의 기능을 향상시키거나 새로운 기능을 추가하기 위한 스트림으로 실제 데이터를 주고받는 스트림이 아니기 때문에 독립적으로 데이터의 입출력을 수행할 수 없다.
입력 스트림 | 출력 스트림 | 설명 |
BufferedReader | BufferedWriter | 버퍼를 이용한 입출력 |
PushbackReader | X | 다른 입력 스트림에 버퍼를 이용하여 push back이나 unread와 같은 기능을 추가함. |
X | PrintWriter | 다른 출력 스트림에 버퍼를 이용하여 다양한 데이터를 출력하기 위한 기능을 추가함. |
FilterReader | FilterWriter | 필터를 이용한 입출력 |
BufferedReader와 BufferedWriter
유니코드의 문자 데이터를 처리하는 스트림의 입출력 효율을 높이기 위해 버퍼를(char[])를 사용하는 보조스트림
- BuffredReader와 BufferedWriter는 BufferedInputStream와 BufferedOutputStream 비슷한 기능을 제공한다.
- 라인(line)단위의 입출력이 편리하다.
- 보조스트림을 닫으면 기반스트림도 닫힌다.
BufferedReader
생성자/메서드 | 설명 |
BufferedReader(Reader in) | 주어진 Reader의 인스턴스를 입력 소스(input source)로하여 BufferedReader의 버퍼를 갖는 BufferedReader 인스턴스를 생성한다.(버퍼의 크기를 지정해 주지 않아 기본값인 8192 char 크기의 버퍼를 갖게 된다.) |
BufferedReader(Reader in, int size) | 주어진 Reader의 인스턴스를 입력 소스(input source)로하여 지정된 크기(char 단위)의 버퍼를 갖는 BufferedReader 인스턴스를 생성한다. |
readLine() | 버퍼으로부터 한 줄을 읽어 문자열을 리턴해주는 메소드 |
BuffredReader의 readLine()을 사용하면 데이터를 라인단위로 읽어올 수 있다는 장점이 있다.
- readLine()의 리턴 타입은 String으로 고정되기에 String이 아닌 다른 타입이 필요하다면 형변환이 필요하다.
BufferedWriter
생성자/메서드 | 설명 |
BufferedWriter(Writer out) | 주어진 Writer 인스턴스를 출력소스(ouput source)로 하여 BufferedWriter 의 버퍼를 갖는 BufferedWriter인스턴스를 생성한다. (버퍼의 크기를 지정해 주지 않아 기본값인 8192 char 크기의 버퍼를 갖게 된다.) |
BufferedWriter(Writer out, int sz) | 주어진 Writer 인스턴스를 출력소스(ouput source)로 하여 지정된 크기(char)의 버퍼를 갖는 BufferedWriter인스턴스를 생성한다. |
newLine() | 라인 구분자(개행문자)를 출력한다. |
flush() | 버퍼의 모든 내용을 출력소스에 출력한 다음, 버퍼를 비운다. |
close() | flush()를 호출해서 버퍼의 모든 내용을 출력소스에 출력하고, 인스턴스가 사용하던 모든 자원을 반납한다. |
BufferedWriter또한 write()를 통한 출력이 바로 출력되지 않고 BufferedWriter의 버퍼에 저장된다. 내부 버퍼에 데이터를 쌓아두었다가 버퍼의 내용이 가득차면 출력소스로 출력한다.
- 버퍼가 가득 차면, 그 때 버퍼의 모든 내용을 출력 소스에 출력한다.
버퍼가 가득 찼을때만 출력소스에 출력을 하기 때문에, 마지막 출력 부분이 출력소스에 쓰여지지 못하고 버퍼에 남아있는 채로 프로그램이 종료될 수 있다는 점을 주의해야 한다.
- 따라서 프로그램에서 모든 출력 작업을 마친 후 BufferedWriter 에 close()나 flush()를 호출해서 마지막에 버퍼에 있는 모든 내용이 출력소스에 출력되도록 해야 한다
InputStreamReader와 OutputStreamWriter
바이트 기반 스트림을 문자 기반 스트림으로 연결시켜주는 역할을 한다.
- 바이트기반스트림의 데이터를 지정된 인코딩의 문자데이터로 변환하는 작업을 수행한다.
- 인코딩(encoding)을 변환하여 입출력할 수 있게 해준다.
생성자/메서드 | 설명 |
InputStreamReader(InputStream in) | Os에서 사용하는 기본 인코딩의 문자로 변환하는 InputStreamReader을 생성한다. |
InputStreamReader(InputStream in, String encoding) | 지정된 인코딩을 사용하는 InputStreamReader를 생성한다. |
String getEncoding() | InputStreamReader의 인코딩을 알려준다. |
생성자/메서드 | 설명 |
OutputStreamReader(OutStream out) | Os에서 사용하는 기본 인코딩의 문자로 변환하는 OutputStreamReader 을 생성한다. |
OutputStreamReader (OutStream out, String encoding) | 지정된 인코딩을 사용하는 OutputStreamReader 를 생성한다. |
String getEncoding() | OutputStreamReader 의 인코딩을 알려준다. |
라인 단위위의 입력을 받기 위해서는 BufferedReader의 readLine()을 사용하면 편리하다.
- BufferedReader와 InputStream인 System.in을 연결하기 위해 InputStreamReader를 사용하였다.
- jdk.1.5부터 제공된 Scanner를 사용하면 간단하게 처리 가능하지만 성능의 차이가 있다.
'Java' 카테고리의 다른 글
[JAVA] 표준 입출력과 File 클래스, 직렬화(Serialization) (0) | 2024.01.18 |
---|---|
[JAVA] 버퍼 스트림 (0) | 2024.01.18 |
[JAVA] 쓰레드의 동기화(synchronization) (0) | 2024.01.18 |
[JAVA] 쓰레드(thread) (0) | 2024.01.18 |
[JAVA] 애너테이션(Annotation) (0) | 2024.01.10 |