카테고리 없음

[TIL] 2022년 9월 21일 수요일

2022. 9. 21. 22:57

4. 문자기반 스트림

- 문자기반 스트림은 바이트 단위로 데이터를 다루던 바이트기반 스트림 달리 문자 단위로 데이터를 다루는 점을 제외하면 사용 방법은 동일

- 그렇다면 문자기반 스트림과 바이트기반 스트림은 무엇이 다를까?

→ 바이트기반 스트림은 데이터를 읽어올 때 read(byte[] b)을 이용하고 문자기반 스트림은 read(char[] c)를 이용

 

https://stackoverflow.com/questions/2428076/what-is-the-difference-between-a-stream-and-a-reader-in-java

Stream클래스는 byte 기반 클래스로 byte 단위로 데이터를 읽고 쓰기때문에 이미지처럼 이진수로 된 파일을 다루거나 작은 데이터를 다루는데 유용하다. Reader/Writer 클래스는 문자 기반 클래스로 하나의 문자씩 데이터를 읽고 쓰기 때문에 텍스트 파일이나 다른 텍스트 스트림을 다루는데 유용하다.

https://stackoverflow.com/questions/4367539/what-is-the-difference-between-reader-and-inputstream

InputStream은 데이터를 byte 단위로 읽고 어떤 번역의 과정을 거치지 않는다. 이진 파일이나 이미지 파일을 읽을 때 InputStream을 사용한다. Reader는 문자기반 스트림으로 Input Stream 원본에서 디코딩 과정을 거쳐 유니코드 문자로 돌려준다. 텍스트로의 어떤 유형이든 Reader를 사용한다.

 

사실 책에 char가 2byte라서 무조건 문자기반 스트림이 2byte 단위로 스트림을 처리하는 것이 아니고 Reader/Writer 클래스와 그 자식 클래스들은 특정 인코딩을 읽어서 유니코드로 변환하고 유니코드를 특정 인코딩으로 변환하여 저장한다는 이야기가 나와서 그걸 찾고싶었는데 찾지 못했다. 

https://stackoverflow.com/questions/4367539/what-is-the-difference-between-reader-and-inputstream

한가지 더 보자면 'a‡a'는 우리가 보기에 3글자이지만 ‡가 유니코드 문자라서 InputStream으로 'a‡a'를 읽으면 a는 바이트의 범위에 들지만 '‡'는 8225로 바이트를 초과해 226, 128, 161 총 3 byte가 된다. 하지만 Reader로 읽으면 8227이 되어 97 8227 97이 된다.

 

4.1 Reader와 Writer

- Reader 클래스와 Writer 클래스 모두 Object 클래스의 자식 클래스로 Buffered, CharArray, Filter, Stream, Piped, String Reader/Writer를 부모 클래스

- Reader 클래스는 URLReader, Writer 클래스는 PrintWriter로 각각 고유한 클래스의 부모 클래스

 

자료형 메서드 설명
abstract void close() Closes the stream and releases any system resources associated with it.
void mark(int readAheadLimit) Marks the present position in the stream.
boolean markSupported() Tells whether this stream supports the mark() operation
static Reader nullReader() Returns a new Reader that reads no characters.
int read() Reads a single character.
int read(char[] cbuf) Reads characters into an array.
abstract int read(char[] cbuf, int off, int len) Reads characters into a portion of an array.
int read(CharBuffer target) Attempts to read characters into the specified character buffer.
boolean ready() Tells whether this stream is ready to be read.
void reset() Resets the stream.
long skip(long n) Skips characters.
long transferTo(Writer out) Reads all characters from this reader and writes the characters to the given writer in the order that they are read.
자료형 메서드 설명
Writer append(char c) Appends the specified character to this writer.
Writer append(CharSequence csq) Appends the specified character sequence to this writer.
Writer append(CharSequence csq, int start, int end) Appends a subsequence of the specified character sequence to this writer.
abstract void close() Closes the stream, flushing it first.
abstract void flush() Flushes the stream.
static Writer nullWriter() Returns a new Writer which discards all characters.
void write(char[] cbuf) Writes an array of characters.
abstract void write(char[] cbuf, int off, int len) Writes a portion of an array of characters.
void write(int c) Writes a single character.
void write(String str) Writes a string.
void write(String str, int off, int len) Writes a portion of a string.

 

4.2 FileReader와 FileWriter

- Reader와 Writer 클래스 페이지에 FileReader와 FileWriter가 없어 이상하다 생각했는데 Reader와 Writer의 자식 클래스인InputStreamReader/OutputStreamWriter의 자식 클래스

- 문자 파일을 텍스트로 읽고, 텍스트를 문자 파일로 씀

- byte로 인코딩 할 때는 특정 charset이나 플랫폼 기반 charset을 따름

 

 

4.3 PipedReader와 PipedWriter

- 쓰레드 간 데이터를 주고받을 때 사용

- 입력 스트림과 출력스트림을 생성한 다음 둘 중 하나의 스트림에 connect()를 호출해서 하나의 스트림으로 연결하여 데이터를 주고받고, 입출력을 마친 뒤 한쪽 스트림만 닫아도 나머지 스트림이 닫힘

- 생성자를 선언할 때 매개변수로 아무것도 받지 않거나 정수로 pipeSize만 받으면 아직 연결되지 않음을 의미함

더보기
import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;
import java.io.StringWriter;

public class PipedReaderWriter {
    public static void main(String[] args) {
        InputThread inThread = new InputThread("InputThread");
        OutputThread outThread = new OutputThread("OutputThread");

        inThread.connect(outThread.getOutput());

        inThread.start();
        outThread.start();
    }
}

class InputThread extends Thread{
    PipedReader input = new PipedReader();
    StringWriter sw = new StringWriter();

    InputThread(String name){
        super(name);
    }

    public void run(){
        try{
            int data = 0;

            while ((data=input.read()) != -1)
                sw.write(data);

            System.out.println(getName() + " received : " + sw.toString());
        }catch (IOException e){}
    }

    public PipedReader getInput(){
        return input;
    }

    public void connect(PipedWriter output){
        try {
            input.connect(output);
        }catch (IOException e){}
    }
}

class OutputThread extends Thread{
    PipedWriter output = new PipedWriter();

    OutputThread(String name){
        super(name);
    }

    public void run() {
        try {
            String msg = "Hello!";
            System.out.println(getName() + " sent : " + msg);
            output.write(msg);
            output.close();
        }catch (IOException e) { }
    }

    public PipedWriter getOutput(){
        return output;
    }

    public void connect(PipedReader input){
        try {
            output.connect(input);
        }catch (IOException e) { }
    }
}