Java IO <6 - Reader>

devhan·2023년 9월 3일
0

자바 I/O 입문

목록 보기
6/7

막연하게만 사용하던 I/O를 조금 더 이해해보고자 작성한 글입니다.
기본적으로 I/O는 O/S 레벨에서 이루어지고 byte를 다룬다는 것을 생각야해합니다.


Reader

byte를 다루는 InputStream과 달리 Reader 클래스는 String을 다룰 때 사용되는 클래스이다.
Reader클래스들은 InputStream을 내부에서 사용하거나 랩핑하여 사용한다.

Reader = InputStream + String 핸들링


1. FileReader

영문을 입력할 때와 한글을 읽을 때를 각각 살펴보자.

  // test.txt
  this is a test sentence
  한글 테스트 입니다.


  public static void main(String[] args) throws IOException {
    FileInputStream fileStream = new FileInputStream("test.txt");

    int data = fileStream.read();
    System.out.println("stream: " + (char) data);

    FileReader fileReader = new FileReader("test.txt");
    int res = fileReader.read();
    System.out.println("reader: " + (char) res);

  }

- 영문의 경우

정확히는 ASCII 문자셋에 포함되는 글자를 입력하는 경우이다.
이때는 두 코드 결과값의 차이가 없다. 왜냐하면 1byte를 읽어도 완성된 문자이고, 1글자를 읽어도 1byte이기 때문이다.

	// text가 "this is a test sentence" 일 경우
    System.out.println("stream: " + (char) data); // t
    
    System.out.println("reader: " + (char) result); // t

- 한글의 경우

정확히는 유니코드에서 1byte이상으로 표현되는 문자의 경우이다.
InputStream의 경우는 인코딩결과와 상관없이 1byte를 읽기 때문에 입력한 글자와 다른 글자가 표현되지만, FileReader의 경우는 글자 단위로 읽기 때문에 인코딩을 감안한 byte를 읽는다.

	// text가 "한글 테스트 입니다." 일 경우
    System.out.println("stream: " + (char) data); // í
    
    System.out.println("reader: " + (char) result); // 한



2. InputStreamReader

다른 Reader클래스를 사용하기 위해 인터페이스 변환이 필요한 경우와 특정 인코딩을 사용하기 위한 경우 2가지에 사용될 수 있다.

- 인터페이스 변환 (브릿징)

이전 글에서 작성한 소켓 통신 서버 코드이다. String을 다루는 경우 BufferedReader를 사용하면 훨씬 손쉽게 InputStream을 핸들링할 수 있다.
이 때, BufferedReader는 생성시에 Reader 타입을 인자로 받기 때문에 InputStream을 InputStreamReader 타입으로 변경이 필요하다.

public static void main(String[] args) throws IOException {
      ServerSocket serverSock = new ServerSocket(port);

      while(true) {
        Socket socket = serverSock.accept();

        InputStream in = socket.getInputStream();
        Reader reader = new InputStreamReader(in); // 인터페이스 변경
        BufferedReader bufReader = new BufferedReader(reader);

        String msg = "";
        while((msg = bufReader.readLine()) != null) {
          System.out.println(msg);
        }
}

- 인코딩 방법 설정

기본적으로 Reader는 JVM에 설정되있는 encoding방법으로 문자열 처리를 하기 때문에 별도의 encoding 방법을 사용하고 싶다면 InputStreamReader가 필요하다.

  public static void main(String[] args) throws IOException {
    InputStream in = System.in;
    InputStreamReader reader = new InputStreamReader(in, StandardCharsets.UTF_8);

    int data = reader.read();
    System.out.println((char) data);

  }

InputStreamReader의 2번째 인자로 전달하는 인코딩 방법에 따라 결과가 달라진다.




3. BufferedReader

기본 매커니즘은 BufferedInputStream과 같지만, 추가적으로 readLine 메소드를 제공한다.
문장 단위로 결과를 반환하고, 더이상 문장이 없을 경우 null을 반환한다.

  • 파일
public static void main(String[] args) throws IOException {
	FileReader reader = new FileReader("./src/ttest.txt");
    BufferedReader bufReader = new BufferedReader(reader);

    String data;
    while((data = bufReader.readLine()) != null) {
      System.out.println(data);
    }
}
  • 네트워크
public static void main(String[] args) throws IOException {
      ServerSocket serverSock = new ServerSocket(port);

      while(true) {
        Socket socket = serverSock.accept();

        InputStream in = socket.getInputStream();
        Reader reader = new InputStreamReader(in); // 인터페이스 변경
        BufferedReader bufReader = new BufferedReader(reader);

        String msg = "";
        while((msg = bufReader.readLine()) != null) {
          System.out.println(msg);
        }
}



4.StringReader

String타입을 글자단위의 바이트로 읽는다.
언뜻 toCharrArray로 바꿔서 사용할 수도 있다는 생각이 들지만, reader 타입이기 때문에 다른 stream들과 연계하기 사용하기 좋은 이점이 있다.

public static void main(String[] args) throws IOException {
	String msg = "한글이다";
    StringReader reader = new StringReader(msg);

    int data;
    while ((data = reader.read()) != -1) {
      System.out.println(data);
    }
}


Summary

Reader 클래스는 Stream에 String 핸들링 로직을 더해서, String 관련 작업을 편하게 해주는 클래스이다.
BufferedReader를 사용하면 readLine을 사용할 수 있다.

profile
한번에 한가지씩

0개의 댓글

관련 채용 정보