순간을 성실히, 화려함보단 꾸준함을

13주차 과제: I/O 본문

백기선님과 함께 하는 자바 스터디

13주차 과제: I/O

폭발토끼 2021. 7. 21. 22:46

목표

자바의 Input과 Ontput에 대해 학습하세요.

학습할 것(필수)

  1. 스트림 (Stream) / 버퍼 (Buffer) / 채널 (Channel) 기반의 I/O
  2. InputStream과 OutputStream
  3. Byte와 Character 스트림
  4. 표준 스트림 (System.in, System.out, System.err)
  5. 파일 읽고 쓰기

스트림 (Stream) / 버퍼 (Buffer) / 채널 (Channel) 기반의 I/O

입출력이란?

- I/O란 Input 과 Output의 약자로 입력과 출력, 간단히 줄여서 입출력이라고 한다. 입출력은 컴퓨터 내부 또는 외부의 장치와 프로그램간의 데이터를 주고 받는 행위를 뜻한다.

1) 스트림(Stream)

자바에서는 데이터를 전송하기 위해선 두 대상을 연결하고 데이터를 전송할 수 있는 무엇인가가 필요하다. 이게 바로 스트림(Stream) 이다.

스트림이란?

- 데이터를 운반하는데 사용되는 통로이다.

스트림이라는 단어는 연속적인 데이터의 흐름을 물에 비유해서 붙여진 이름인데, 물이 한쪽 방향으로만 흐르는 것과 같이 스트림은 단방향 통신만 가능하기 때문에 하나의 스트림으로 입력과 출력을 동시에 처리할 수 없다.

이 때문에 입력스트림(Input Stream) 과 출력스트림(Output Stream) 모두 2개가 필요하다.

스트림은 먼저 보낸 데이터를 먼저 받게 되어 있으며 중간에 건너뜀 없이 연속적으로 데이터를 주고받는다.
큐(queue)와 같은 FIFO(First In First Out) 구조로 되어 있다고 생각하면 된다.

2) 버퍼(Buffer)

버퍼란?

- 임시공간을 의미한다. 두 대상이 데이터를 주고 받는데 중간에 버퍼가 존재하며 이는 통신의 속도를 줄일 수 있는 장점이 존재한다.

예를 들어보면 현재 우리는 공사판에 있다고 가정해보자. 눈앞에 보이는 벽돌을 전부 건설현장으로 옮겨야 되는데 벽돌 하나씩 집어서 왔다갔다 하는 것이 효율적인가??전혀 아니다. 그래서 우린 벽돌을 담을 수 있는 수레하나를 옆에두고 수레가 가득 찰때까지 벽돌을 쌓는다. 그리고 수레가 가득 찼다면 그때 그 수레를 건설현장으로 옮기는 것이다. 벽돌을 하나씩 집어서 옮기는 것보다 훨씬 효율적이고 빠른 시간안에 옮길 수 있게 되는 것이다.

이때 바로 수레가 버퍼(Buffer) 의 역할이 된다.

키보드를 통해 입력이 발생할때 마다 한 문자씩 버퍼에 쌓이게 된다. 만약 버퍼가 가득차거나, 개행문자를 만나게 되면 버퍼에 쌓여있던 내용을 한번에 전송하게 되는 것이다.
(백준에서 입출력을 받을때 Scanner를 사용하지 말고 BufferedReader 를 사용하라는 이유가 이때문이다)

3) 채널(Channel)

채널이란?

- 데이터가 통과하는 쌍방향 통로이며, 채널에서 데이터를 주고 받을 때 사용 되는 것이 버퍼이다.

채널에는 소켓과 연결된 SocketChannel, 파일과 연결된 FileChannel, 파이프와 연결된 Pipe.SinkChannel, Pipe.SourceChannel 등이 존재하며, 서버소켓과 연결된 ServerSocketChannel 또한 존재한다.

+IO 와 NIO

NIO란?

- Java4 부터 새로운 입출력(New Input Output)이라는 뜻에서 java.nio 패키지에 포함이 되었다.

IO는 스트림 기반이며, NIO는 채널 기반이다. 체널은 스트림과 다르게 양방향 입출력이 가능

IO방식에서는 각각의 스트림에서 read() 와 write()가 호출이 되면 데이터가 입력이 되고, 쓰레드는 블로킹(멈충) 상태가 되버린다. 이때 작업이 끝날때까지 무작정 기다리는 현상이 발생한다. 이때가지는 IO쓰레드는 사용할 수 없게 되고, 인터럽트 또한 할 수 없다.
블로킹을 해제하려면 스트림을 닫는 방법밖에 존재하지 않았다.
그러나 NIO에서는 블로킹 상태일때 인터럽트를 사용하여 빠져나올 수 있다.

구분IONIO
입출력 방식스트림채널
버퍼 방식Non - BufferBuffer
비동기 방식 지원XO
Blocking/Non-Blocking 방식Blocking OnlyBoth
사용 케이스연결 클라이언트가 작고, IO가 큰경우(대용량)연결 클라이언트가 많고, IO 처리가 적은 경우(저용량)

InputStream과 OutputStream

스트림은 바이트단위로 데이터를 전송하며 입출력 대상에 따라 다음과 같은 입출력스트림이 존재한다.

입력스트림출력스트림입출력 대상의 종류
FileInputStreamFileOutputStream파일
ByteArrayInputStreamByteArrayOutputStream메모리(byte배열)
PipedInputStreamPipedOutputStream프로세스(프로세스간의 통신)
AudioInputStreamAudioOutputStream오디오장치

이들은 모두 InputStream 또는 OutputStream의 자손들이며, 각각 읽고 쓰는데 필요한 추상메소드를 자신에 맞게 구현해 놓았다.

InputStreamOutputStream
abstract int read()abstract void write(int b)
int read(byte[] b)void write(byte[] b)
int read(byte[] b,int off,int len)void write(byte[] b,int off,int len)
  • read() : 입력 스트림으로부터 1바이트를 읽어서 바이트를 리턴
  • read(byte[] b) : 입력 스트림으로부터 읽은 바이트들을 매개값으로 주어진 바이트 배열 b에 저장하고 실제로 읽은 바이트 수를 리턴
  • read(byte[] b, int off,int len) : 입력 스트림으로부터 len개의 바이트만큼 읽고 매개값으로 주어진 바이트 배열 b[off] 부터 len개까지 저장, 그리고 실제로 읽은 바이트 수인 len개를 리턴, 만약 len개를 모두 읽지 못했더라면 실제로 읽은 바이트 수를 리턴
  • write() : 출력 스트림으로부터 1바이트를 보냄
  • write(byte[] b) : 출력 스트림으로부터 주어진 바이트 배열 b의 모든 바이트를 보냄
  • write(byte[] b, int off, int len) : 출력 스트림으로 주어진 바이트 배열 b[off] 부터 len개까지의 바이트를 보냄

Byte와 Character 스트림

Byte Stream 이란?

- 데이터를 byte 단위로 주고 받는 것을 뜻한다. 1byte = 8bit 인 byte를 뜻하며 위에서 언급한 InputStream 과 OutputStream이 대표적인 Byte Stream에 해당한다. 대부분 InputStream 과 OutputStream으로 끝난다.

Character Stream이란?

- Character Stream은 Reader와 Writer를 가지고 있다. 모두 문자단위로 인코딩 처리를 하는 Stream들이다.

파일 읽고 쓰기

입출력 효율을 위해 Buffered 계열의 보조 스트림을 함께 사용하는 것이 좋다. 또한, 텍스트 파일인 경우 문자 스트림 클래스들을 사용하면 되고, 바이너리 파일인 경우 바이트 스트림을 기본적으로 사용한다.

//텍스트파일인 경우
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
String s;
while ((s = br.readLine()) != null) {
    bw.write(s + "\n");
}
//이진파일인 경우
BufferedInputStream is = new BufferedInputStream(new FileInputStream("a.jpg"));
BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream("b.jpg"));
byte[] buffer = new byte[16384];
while (is.read(buffer) != -1) {
    os.write(buffer);
}

Reference

https://story.stevenlab.io/96
https://bingbingpa.github.io/java/whiteship-live-study-week13/

'백기선님과 함께 하는 자바 스터디' 카테고리의 다른 글

14주차 과제: 제네릭  (0) 2021.07.31
[리뷰] 13주차 : I/O  (0) 2021.07.25
[리뷰]12주차 : 애노테이션  (0) 2021.07.15
12주차 과제: 애노테이션  (0) 2021.07.12
[리뷰] 11주차 : Enum  (0) 2021.07.10