본문 바로가기
Develop/Java

[Java] 입출력(I/O)과 버퍼(Buffer)

by 연로그 2022. 9. 5.
반응형

서론

 

 ByteArrayOutputStream과 BufferedOutputStream의 차이점에 대한 질문을 받았다. 내가 Java의 입출력 시스템과 buffer에 대한 이해도가 떨어진다는 상태를 자각하게 되었다. 이를 공부하는 내용을 작성하려고 한다.

 

목차

  1. stream이란?
  2. InputStream & OutputStream
  3. InputStreamReader & OutputStreamWriter
  4. buffer란?
  5. BufferedInputStream & BufferedOutputStream 
  6. BufferedReader & BufferedWriter

 


Java의 입출력

 java에서의 입출력은 Stream을 통해 이루어진다.

 

1. stream이란?

  • 데이터를 운반하는데 사용되는 연결 통로
  • stream 이름의 어원: 데이터의 흐름이 물의 흐름 같이 단방향 통신만 가능
    (= 하나의 stream은 입, 출력 동시에 처리 불가능)
  • 먼저 보낸 데이터를 먼저 받는 FIFO 구조

 

img:https://medium.com/@nilasini/java-nio-non-blocking-io-vs-io-1731caa910a2

  • Source: 데이터 시작점
  • Sink: 데이터 종착점
  • Stream: source와 sink를 연결한 것
    • input stream: 입력을 위한 스트림
    • output stream: 출력을 위한 스트림

 

 

2. InputStream & OutputStream

InputStream과 OutputStream은 abstract class이다. 이를 상속받는 클래스들은 입출력 대상에 따라 다양하게 존재한다. (아래 표 이외에도 다양한 I/O Stream이 존재) 해당 클래스의 중요한 점은 입출력 단위가 byte라는 것이다. 

입출력 대상의 종류 입력 스트림 출력 스트림
파일 FileInputStream FileOutputStream
메모리 (byte[]) ByteArrayInputStream ByteArrayOutputStream
프로세스 PipedInputStream PipedOutputStream

 

주요 메서드로는 값을 읽고 쓰는 read와 write가 있다.

InputStream OutputStream
abstract int read() abstract int write()
int read(byte[] b) int write(byte[] b)
int read(byte[] b, int off, int len) int write(byte[] b, int off, int len)

 

추가적으로 OuputStream에는 close()와 flush()이라는 메서드가 존재한다. 둘 다 리소스를 해제해주는 역할을 하지만 close()는 stream을 영구적으로 닫아 재사용할 수 없는 상태로 만든다.

 

예제 코드

테스트 코드를 잘 모르는 사람들은 assertThat 없이 System.out.println()을 이용해 bytes와 outputStream.toByteArray()를 찍어보기를 바란다.
@Test
void test() throws IOException {
    byte[] bytes = {0, 1, 2, 3, 4, 5};
    ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); // bytes를 inputStream에 저장
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream(bytes.length);

    int data = 0;
    while ((data = inputStream.read()) != -1) { // 읽어올 수 있는 값이 존재하지 않으면 -1이 반환됨
        outputStream.write(data); // 읽어온 byte를 outputStream에 쓰기
    }

    assertThat(bytes).isEqualTo(outputStream.toByteArray()); // 동일한지 검사
}

 

 

3. InputStreamReader & OutputStreamWriter

InputStream과 OutputStream으로는 문자를 처리하기 어려움을 겪을 수 있다. 이를 보완하기 위해 등장한 것이 Reader와 Writer인데 먼저 어떤 문제점이 있는지 살펴보자.

 

  • Java에서는 char형이 2byte이다.
    (Input/OutputStream은 1 byte 단위로 읽어온다는 점을 기억하자.)
  • 인코딩 정보가 필요하다.

 

InputStreamReader의 생성자를 살펴보았다. 내가 인코딩과 관련된 정보를 주지 않아도 default charset을 가져와 이용하는 모습을 확인할 수 있다.

public InputStreamReader(InputStream in) {
    super(in);
    sd = StreamDecoder.forInputStreamReader(in, this,
            Charset.defaultCharset()); // ## check lock object
}

 

 

4. buffer란?

img:http://www.tcpschool.com/c/c_io_console

  • buffer; 완충 장치; 완화하다
  • 데이터를 전송하는 동안 일시적으로 해당 데이터를 보관하는 메모리의 임시 공간
  • 데이터를 하나씩이 아닌 묶어서 한 번에 전달해 전송 시간의 단축
  • 버퍼를 쓰는게 항상 좋은 것은 아님
    (ex: 빠른 응답이 필요한 게임 등)

 

5. BufferedInputStream & BufferedOutputStream 

 InputStream / OutputStream의 성능 향상을 위해 buffer가 적용되었다. InputStream과 마찬가지로 byte 단위로 읽는다.

 

6. BufferedReader & BufferedWriter

 해당 클래스는 InputStream을 문자 단위로 처리하기 어려운 점을 보완하기 위해 나온 InputStreamReader같은 존재이다. BufferedInputStream과 BufferedOutputStream을 문자 단위로 처리하기 편하도록 만들어졌으며 사용 방법이나 메서드 등에 대한 설명은 이 링크에서 한다.

 

[Java] BufferedReader, BufferedWriter

프로그래머스 코테는 파라미터를 알아서 넘겨 받도록 되어있는데.. 백준은 직접 입력 받아야했다. Scanner와 sysout을 쓰다가 속도가 너무 느리게 나와서 BufferedReader/Writer에 대해 알아보려고 한다.

yeonyeon.tistory.com

 

 


참고

반응형