Java :: I/O :: 1. 자바에서의 입출력

김병철·2022년 9월 15일
0

Java

목록 보기
8/20

Java의 정석 3판을 보며 공부한 내용을 정리하였습니다.
남궁성님께 많이 배우고 있습니다.

Chapter 15 입출력 I/O

자바에서의 입출력

1.1 입출력 ?

Input과 Output의 약자로 입력과 출력. 간단히 입출력이라 한다.
입출력은 내부 또는 외부의 장치와 프로그램간의 데이터를 주고받는 것을 말한다.
EX ) 키보드로 데이터 입력 받기, System.out.println()으로 화면에 출력하기 등

1.2 스트림(stream)

자바에서 입출력을 수행하려면(어느 한 쪽에서 다른 쪽으로 데이터를 전달하려면) 두 대상을 연결하고 데이터를 전송할 수 있는 무언가가 필요한데, 이것을 스트림(stream)이라 정의했다.
즉, 스트림이란 데이터를 운반하는데 사용되는 연결통로이다.

  • 단방향 통신만 가능하다.
    (입력과 출력을 동시에 처리할 수 없다. -> 입 출력을 동시에 수행하려면 2개의 스트림 필요)


그림 15.1 Java애플리케이션과 파일간의 입출력

  • 스트림은 중간에 건너뜀 없이 연속적으로 데이터를 주고 받는다.

  • FIFO(First In First Out) 구조

1.3 바이트기반 스트림 - InputStream, OutputStream

스트림은 바이트단위로 데이터를 전송하며 입출력 대상에 따른 스트림이 있다.


# 입력 / 출력스트림 종류

  • 파일 :
    -> FileInputStream / FileOutputStream

  • 메모리(byte배열) :
    -> ByteArrayInputStream / ByteArrayOutputStream

  • 프로세스(프로세스간 통신) :
    -> PipedInputStream / PipedOutputStream

  • 오디오 장치 :
    -> AudioInputStream / AudioOutputStream

어떤 대상에 대해 작업할 것인지에 따라 해당 스트림을 선택해서 사용하면 된다.
이 스트림들 모두 InputStream 또는 OutputStream의 자손들이며 각각 읽고 쓰는데 필요한 추상메소드를 구현해 놓았다.

자바에서는 java.io패키지를 통해 많은 종류의 입출력 관련 클래스를 제공하며,
표준화된 방법을 제공하여 대상이 달라도 동일하게 프로그래밍할 수 있다.

# InputStream과 OutputStream에 정의된 읽기/쓰기 수행 메소드

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

read()와 write(int b)를 추상메소드로 구현한 이유는 입출력의 대상에 따라 읽고 쓰는 방법이 다를 것이기 때문에 각 상황에 알맞게 구현하라는 의미이다.

read()와 write(int b)를 제외한 메소드는 추상메소드가 아니니 그냥 사용해도 된다고 착각해서는 안 된다. 사실 read()와 write(int b)를 이용하여 구현한 것들이기 때문에 read()와 write(int b)가 구현되어야 다른 메소드도 사용할 수 있다.

public abstract class InputStream {
	...
    // 입력스트림으로부터 1byte를 읽어서 반환한다. 읽을 수 없으면 -1을 반환.
    abstract int read();
    
    // 입력스트림으로부터 len개의 byte를 읽어서 byte배열 b의 off위치부터 저장한다.
    int read(byte[] b, int off, int len) {
    	...
        for (int i = off; i < off+len; i++) {
        	// read()를 호출해서 데이터를 읽어서 배열을 채운다.
            b[i] = (byte)read();
    	}
    }
    ...
    // 입력스트림으로부터 byte배열 b의 크기만큼 데이터를 읽어서 배열 b에 저장한다.
    int read(byte[] b) {
      	return read(b, 0, b.length);
    }
    ...
}

read(byte[] b, int off, int len) 에서 read()를 호출하는 것과
read(byte[] b)에서 read(byte[] b, int off, int len)를 호출하는 것을 확인할 수 있다.

결론 : read()는 반드시 구현되어야 하는 핵심적인 메소드이다.


1.4 보조 스트림

스트림의 기능을 보완하기 위한 보조 스트림이 있다.
보조 스트림실제 데이터를 주고받는 스트림은 아니고, 스트림의 기능을 향상시키거나 새로운 기능을 추가할 수 있다.

스트림을 먼저 생성한 후 보조 스트림을 생성하여 사용해야 한다.

# 보조스트림 사용 예시

'test.txt'파일을 읽기 위해 FileInputStream을 사용할 때, 성능 향상을 위해 BufferedInputStream을 사용하는 코드

// 먼저 기반 스트림을 생성
FileInputStream fis = new FileInputStream("test.txt");

// 기반 스트림을 이용하여 보조 스트림 생성
BufferedInputStream bis = new BufferedInputStream(fis);

bis.read();		// 보조 스트림인 BufferedInputStream으로부터 데이터를 읽는다.

보조 스트림인 BufferedInputStream이 입력 기능을 수행한 것처럼 보이지만,
실제 입력 기능은 FileInputStream이 수행하고 BufferedInputStream은 버퍼만 제공한다.

버퍼를 사용한 입출력과 사용하지 않은 입출력의 성능 차이가 커서 대부분의 경우에 버퍼를 이용한 보조 스트림을 사용한다.

# 보조 스트림 종류

  • 필터를 이용한 입출력 처리
    -> FilterInputStream / FilterOutputStream

  • 버퍼를 이용한 입출력 성능향상
    -> BufferedInputStream / BufferedOutputStream

  • int, float와 같은 기본형 단위(primitive type)로 데이터를 처리하는 기능
    -> DataInputStream / DataOutputStream

  • 두 개의 스트림을 하나로 연결
    -> SequenceInputStream / 출력은 없음

  • 읽어 온 데이터의 라인 번호를 카운트(JDK1.1부터 LineNumberReader로 대체)
    -> LineNumberInputStream / 출력은 없음

  • 데이터를 객체단위로 읽고 쓰는데 사용
    -> ObjectInputStream / ObjectOutputStream

  • 버퍼를 이용하며, 추가적인 print관련 기능(print, printf, println메서드)
    -> 입력은 없음 / PrintStream

  • 버퍼를 이용해서 읽어 온 데이터를 다시 되돌리는 기능(unread, push back to buffer)
    -> PushbackInputStream / 출력은 없음

이 보조 스트림 역시 InputStream / OutputStream 의 자손들이다.


1.5 문자기반 스트림 - Reader, Writer

앞서 알아본 스트림은 바이트 기반 스트림이었다.
바이트 기반 스트림은 입출력의 단위가 1byte라는 뜻이다.

바이트 기반 스트림으로는 2byte의 문자를 처리하는 데 어려움이 있다.
이 점을 보완하기 위해 문자기반 스트림이 제공되며, 문자 데이터를 입출력할 때는 문자기반 스트림을 사용하자

# 바이트 기반 스트림과 문자 기반 스트림 비교

  • InputStream -> Reader

    • FileInputStream -> FileReader
    • ByteArrayInputStream -> CharArrayReader
    • PipedInputStream -> PipedReader
    • StringBufferInputStream(deprecated) -> StringReader
  • OutputStream -> Writer

    • FileOutputStream -> FileWriter
    • ByteArrayOutputStream -> CharArrayWriter
    • PipedOutputStream -> PipedWriter
    • StringBufferOutputStream(deprecated) -> StringWriter

# 바이트기반 스트림과 문자기반 스트림의 읽기/쓰기 수행 메서드

  • InputStream :

    • abstract int read()
    • int read(byte[] b)
    • int read(byte[] b, int off, int len)
  • Reader :

    • int read()
    • int read(char[] cbuf)
    • abstract int read(char[] cbuf, int off, int len)
  • OutputStream :

    • abstract void write (int b)
    • void write (byte[] b)
    • void write (byte[] b, int off, int len)
  • Writer :

    • void write (int c)
    • void write (char[] cbuf)
    • abstract void write (char[] cbuf, int off, int len)
    • void write (String str)
    • void write (String str, int off, int len)

# 바이트 기반 보조 스트림과 문자 기반 보조 스트림

보조 스트림도 문자 기반 스트림이 존재하며 바이트 기반과 다르지 않다.

  • 문자 기반 보조 스트림
    • BufferedReader
    • BufferedWriter
    • FilterReader
    • FilterWriter
    • LineNumberReader
    • PrintWriter
    • PushbackReader
profile
keep going on~

0개의 댓글