본문 바로가기
스터디/[white-ship] 자바 스터디(study hale)

13주차 과제: I/O

by doyoungKim 2021. 2. 20.

목표

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

학습할 것 (필수)

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

 

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

 

IO (Input Output) 입출력

  •  컴퓨터는 입출력 (IO) 포트라고도 하는 하나 이상의 통신 인터페이스를 통해 외부와 통신한다.

https://wiki.dcae.pub.ro/index.php/Input/Output_Streams

 

스트림

  • 통신을 균일하게 처리하기 위해 자바에서는 스트림 개념을 사용.
  • 스트림은 한 엔티티가 소스이고 다른 엔티티가 대상이라는 조건을 가진 두 엔티티 간에 일반적으로 유효한 통신 채널을 만드는 것을 의미한다.
  • 소스는 스트림에 정보를 전송(쓰기) 하고 대상은 스트림에서 수신(읽기) 를 한다.  (FIFO)
  • 스트림의 정의는 스트림의 양끝 (소스 및 대상) 을 정의하여 수행. 두 가지 통신 방향이 있기 때문에 스트림을 입력 스트림과 출력 스트림의 두 가지 범주로 구분할 수 있다.
  • 연속된 데이터의 흐름으로 입출력 진행시 다른 작업을 할 수 없는 블로킹 상태가 됨.

 

NIO (New I/O)

* 자바 1.4버전부터 추가된 API로 넌블로킹(Non-blocking) 처리가 가능하며, 스트림이 아닌 채널(Channel)을 사용한다.

 

블로킹 / 넌블로킹

  • Blocking은 직접 제어할 수 없는 대상의 작업이 끝날 때까지 제어권을 넘겨주지 않는 것이다.
    예를 들어 호출하는 함수가 IO를 요청했을 때 IO처리가 완료될 때까지 아무 일도 하지 못한 채 기다리는 것을 말한다.
  • Non-Blocking은 Blocking과 반대되는 개념이다. 직접 제어할 수 없는 대상의 작업 처리 여부와 상관이 없다.
    예를 들어 호출하는 함수가 IO를 요청한 후 IO처리 완료 여부와 상관없이 바로 자신의 작업을 할 수 있다.

 

채널

  • 데이터가 통과하는 쌍방향 통로이며, 채널에서 데이터를 주고 받을 때 사용되는 것이 버퍼이다.
  • 채널에는 소켓과 연결된 SocketChannel, 파일과 연결된 FileChannel, 파이프로 연결된 Pipe.SinkChannel 과 Pipe.SourceChannel 등이 존재하며, 서버소켓과 연결된 ServerSocketChannel 도 존재한다.

버퍼

  • byte, char, int 등 기본 데이터 타입을 저장할 수 있는 저장소로서, 배열과 마찬가지로 제한된 크기(capacity) 에 순서대로 데이터를 저장한다.
  • 버퍼는 데이터를 저장하기 위한 것이지만, 실제로 버퍼가 사용되는 것은 채널을 통해서 데이터를 주고 받을 때 쓰인다.
  • 채널을 통해서 소켓, 파일 등에 데이터를 전송할 때나 읽어올 때 버퍼를 사용하게 됨으로써 가비지량을 최소화 시킬 수 있게 되며, 이는 가비지 콜렉션 회수를 줄임으로써 서버의 전체 처리량을 증가시켜준다.

 

IO vs NIO 

  • IO의 방식으로 각각의 스트림에서 read() 와 write() 가 호출이 되면 데이터가 입력 되고, 데이터가 출력되기전까지, 쓰레드는 블로킹(멈춤) 상태가 된다. 이렇게 되면 작업이 끝날때까지 기다려야 하며, 그 이전에는 해당 IO 쓰레드는 사용할 수 없게 되고, 인터럽트도 할 수 없다. 블로킹을 빠져나오려면 스트림을 닫는 방법 밖에 없다.
  • NIO 의 블로킹 상태에서는 Interrupt 를 이용하여 빠져나올 수 있다.
구분 IO NIO
입출력 방식 스트림 채널
비동기 방식 지원 X O
Blocking/Non-Blocking 방식 Blocking Only Both
사용 케이스 연결 클라이언트가 적고, IO 가 큰 경우(대용량) 연결 클라이언트가 많고, IO 처리가 작은 경우 (저용량)

 

2. InputStream 과 OutputStream

  • InputStream
    • 바이트 기반 입력 스트림의 최상위 추상 클래스
    • 모든 바이트 기반 입력 스트림은 이 클래스를 상속 받아서 만들어 진다.
    • 버퍼, 파일, 네트워크 단에서 입력되는 데이터를 읽어오는 기능을 수행한다.
public abstract class InputStream{
    public abstract int read() throws IOException;
    public int read(byte b[]) throws IOException;
    public int read(byte b[], int off, int len) throws IOException;
    public long skip(long n) throws IOException;
    public int available() throws IOException;
    public void close() throws IOException;
    public synchronized void mark(int readlimit);
    public synchronized void reset() throws IOException;
    public boolean markSupported();
}

 

메서드 설명
read() 입력 스트림으로 부터 1바이트를 읽어서 바이트를 리턴
read(byte[] b) 입력 스트림으로부터 읽은 바이트들을 매개값으로 주어진 바이트 배열 b 에 저장하고 실제로 읽은 바이트 수를 리턴
read(byte[] b, int off, int len) 입력 스트림으로부터 len 개의 바이트만큼 읽고 매개값으로 주어진 바이트 배열 b[off] 부터 len 개까지 저장. 그리고 실제로 읽은 바이트 수인 len 개를 리턴. 만약 len 개를 모두 읽지 못하면 실제로 읽은 바이트 수를 리턴
close() 사용한 시스템 자원을 반납하고 입력 스트림 닫기

 

  • OutputStream
    • 바이트 기반 출력 스트림의 최상위 추상 클래스
    • 모든 바이트 기반 출력 스트림은 이 클래스를 상속 받아서 만들어 진다.
    • 버퍼, 파일, 네트워크 단으로 데이터를 내보내는 기능을 수행한다.
public abstract class OutputStream{
    public abstract void write(int i) throws IOException;
    public void write (byte b[]) throws IOException;
    public void write (byte b[], int off, int len) throws IOException;
    public long flush() throws IOException;
    public void close() throws IOException;
}

 

메서드 설명
write(int b) 출력 스트림으로부터 1바이트를 보낸다. (b의 끝 1바이트)
write(byte[] b)  출력 스트림으로부터 주어진 바이트 배열 b의 모든 바이트를 보낸다.
write(byte[] b, int off, int len) 출력 스트림으로 주어진 바이트 배열 b[off] 부터 len 개까지의 바이트를 보낸다.
flush() 버퍼에 잔류하는 모든 바이트를 출력한다.
close() 사용한 시스템 자원을 반납하고 입력 스트림 닫기

 

3. Byte 와 Character 스트림

  • Byte Stream
    • binary 데이터를 입출력하는 스트림
    • 데이터 1바이트 단위로 처리
    • 이미지, 동영상 등을 송수신 할 때 주로 사용
  • Character Stream
    • text 데이터를 입출력하는 스트림
    • 데이터는 2바이트 단위로 처리
    • 일반적인 텍스트 및 JSON, HTML 등을 송수신할 때 주로 사용
  • 보조 스트림 
    • FileInputStream 과 FilterOutputStream 을 상속받는 클래스들로 기본 스트림과 결합하여 특정 상황에서 보다 편리하게 사용할 수 있다.
    • BufferedInputStream / BufferedOutputStream: 버퍼를 사용해 입출력 효율과 편의를 위해 사용
    • BufferedReader / BufferdWriter: 라인 단위의 입출력이 편리함
    • InputStreamReader / OutputStreamReader : 바이트 스트림을 문자 스트림처럼 쓸 수 있도록 문자 인코딩 변환을 지원
    • DataInputSream/DataOutputStream: 자바 원시자료형 데이터 처리에 적합

https://blog.naver.com/swoh1227/222237603565
https://blog.naver.com/swoh1227/222237603565

4.  표준 스트림 (System.in, System.out, System.err)

  •  자바에서는 모든 표준 스트림에 java.lang 클래스를 통해 접근할 수 있기에
    표준 입출력 스트림의 경우 java.lang 패키지의 System 클래스 내부에 정적(static) 으로 선언되어 있다.
public final class System {
    public static final InputStream in;
    public static final PrintStream out;
    public static final PrintStream err;
    ....
}      

 

  • System.out 은 콘솔 화면에 문자열을 출력하기 위한 용도로 사용되는 출력 스트림이다.
  • System.in은 키보드의 입력을 받아들이기 위해서 사용되는 입력 스트림이다.
  • System.out 과 System.err
    • 둘다 출력 스트림이다.
    • err 은 버퍼링을 지원하지 않는다. 이것은 err 이 보다 정확하고 빠르게 출력되어야 하기 때문이라고 한다. 버퍼링을 하던 도중 프로그램이 멈추면 버퍼링된 내용은 출력되지 않기 때문이다.

 

5. 파일 읽고 쓰기

  • try with resources 문법을 이용하여 좀더 편하게
try (InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dest)) {
	byte[] buf = new byte[1024];
	int n;
	while ((n = in.read(buf)) >= 0)
	out.write(buf, 0, n);
}

 

 

참조

728x90

댓글