본문 바로가기
👨‍🏫Study/JAVA

[JAVA] 19. NIO 기반 입출력 및 네트워킹(1)

by 코푸는 개발자 2022. 4. 6.
728x90

자바 4부터 새로운 입출력(NIO: Input/Output)이라는 뜻에서 java,nio 패키지가 포함되었는데, 자바 7로 버전업하면서 자바 IO와 NIO 사이의 일관성 없는 클래스 설계를 바로 잡고, 비동기 채널 등의 네트워크 지원을 대폭 강화한 NIO.2 API가 추가되었다. NIO.2는 java,nio2 패키지로 제공되지 않고 기존 java.nio의 하위 패키지(java.nio.channels, java.nio.charset, java.nio.file)에 통합되어 있다.

NIO 패키지 포함되어 있는 내용
java.nio 다양한 버퍼 클래스
java.nio.channels 파일 채널, TCP 채널, UDP 채널 등의 클래스
java.nio.channels.spi java.nio.channels 패키지를 위한 서비스 제공자 클래스
java.nio.charset 문자셋, 인코더, 디코더 API
java.nio.charset.spi java.nio.charset 패키지를 위한 서비스 제공자 클래스
java.nio.file 파일 및 파일 시스템에 접근하기 위한 클래스
java.nio.file.attribute 파일 및 파일 시스템의 속성에 접근하기 위한 클래스
java.nio.file.spi java.nio.file 패키지를 위한 서비스 제공자 클래스

 

19.1.1. IO와 NIO의 차이점

IO와 NIO는 데이터를 입출력한다는 목저은 동일하지만, 방식에 있어서 크게 차이가 난다.

구분 IO NIO
입출력 방식 스트림 방식 채널 방식
버퍼 방식 넌버퍼(non-buffer) 버퍼(buffer)
비동기 방식 지원 안 함 지원
블로킹 / 넌블로킹 방식 블로킹 방식만 지원 블로킹 / 넌블로킹 방식 모두 지원

 

스트림 vs. 채널

IO는 스트림(Stream) 기반이다. 스트림은 입력 스트림과 출력 스트림으로 구분되어 있기 때문에 데이터를 읽기 위해서는 입력 스트림을 생성해야 하고, 데이터를 출력하기 위해서는 출력 스트림을 생성해야 한다.

NIO는 채널(Channel) 기반이다. 채널은 스트림과 달리 양방향으로 입력과 출력이 가능하다. 그렇기 때문에 입력과 출력을 위한 별도의 채널을 만들 필요가 없다. 예를 들어 하나의 파일에서 데이터를 읽고 저장하는 작업을 모두 해야 한다면  FileChannel 하나만 생성하면 된다.

 

넌버퍼 vs. 버퍼

IO에서는 출력 스트림이 1바이트를 쓰면 입력 스트림이 1바이트를 읽는다. 이런 시스템은 대체로 느리다. 이것보다는 버퍼(Buffer: 메모리 저장소)를 사용해서 복수 개의 바이트를 한꺼번에  입력받고 출력하는 것이 빠른 성능을 낸다. 그래서 IO는 버퍼를 제공해주는 보조 스트림인 BufferedInputStream, BufferedOutputStream을 연결해서 사용하기도 한다. NIO는 기본적으로 버퍼를 사용해서 입출력을 하기 때문에 IO보다는 입출력 성능이 좋다. 채널은 버퍼에 저장된 데이터를 출력하고, 입력된 데이터를 버퍼에 저장한다.

 

IO는 스트림에서 읽은 데이터를 즉시 처리한다. 때문에 스트림으로부터 입력된 전체 데이터를 별도로 저장하지 않으면, 입련된 데이터의 위치를 이동해 가면서 자유롭게 이용할 수 없다.

NIO는 읽은 데이터를 무조건 버퍼에 저장하기 때문에 버퍼 내에서 데이터의 위치를 이동해 가면서 필요한 부분만 읽고 쓸 수 있다.

 

블로킹 vs 넌블로킹

  • IO는 read(),write()메소드가 호출하면 스레드가 블로킹된다. 블로킹을 빠져나오기 위해 인터럽트(interrupt) 할 수 없다.
  • NIO는 입출력 작업 시 스레드가 블로킹되지 않는다. 스레드를 인터럽트함으로써 빠져나올 수가 있다.
  • NIO 넌블로킹은 입출력 작업 준비가 완료된 채널만 선택해서 작업 스레드가 처리하기 때문에 작업 스레드가 블로킹되지 않는다.
    • 위의 준비가 완료된었다는 뜻은 버퍼에서 지금 바로 읽고 쓸 수 있는 상태를 말한다.
  • NIO 넌블로킹의 핵심 객체는 멀티플렉서(multiplexor)인 셀렉터(Selector)이다.
    • 셀렉터는 복수 개의 채널 중에서 준비 완료된 채널을 선택하는 방법을 제공한다.

 

IO와 NIO 선택기준

  • IO는 연결 클라이언트 수가 적고, 전송되는 데이터가 대용량이면서 순차적으로 처리될 필요성이 있는 경우 사용
  • NIO는 연결 클라이언트 수가 많고, 하나의 입출력 처리 작업이 오래 걸리지 않는 경우 사용

 

2. 파일과 디렉토리

- NIO는 IO보다 파일의 속성 정보을 읽기 위해 더 많은 클래스와 인터페이스를 제공

 

경로 정의 - Path

- java.nio.file.Path 인터페이스는 NIO의 API에서 파일의 경로를 지정하기 위해서 사용된다.

- Path 구현 객체를 얻기 위해서 java.nio.file.Paths 클래스의 정적 메소드인 get() 메소드를 호출

 

Path path = Paths.get("가져올 파일 경로");

- 가져올 파일 경로는 절대 경로와 상대 경로 모두 사용 가능

 

Path 인터페이스를 통해 가져온 파일의 정보얻기 위한 메소드

 

결과

 

파일 속성 읽기 및 파일, 디렉토리 생성/삭제

  • java.nio.file.Files 클래스는 파일과 디렉토리의 생성 및 삭제, 그리고 이들의 속성을 읽는 메소드를 제공

 

 

 

와치 서비스 - WatchService

  • 디렉토리 내부에서 파일 생성, 삭제, 수정 등의 내용 변화를 감시하는 데 사용
  • 와치 서비스는 일반적으로 파일 변경 통지 메커니즘으로 알려짐

 

WatchService 생성 방법

WatchService watchService = FileSystems.getDefault().newWatchService();

 

  • 생성했다면 감시가 필요한 디렉토리의 Path 객체에서 register()메소드로 WatchService를 등록한다.
    • 어떤 변화(생성, 삭제, 수정)를 감시할 것인지를 StandardWatchEventKinds 상수로 지정할 수 있다.

 

ex. path 변수 안에 Path 객체를 통한 디렉토리의 경로 담겨 있다.

path.register(watchService, StandardWatchEventKinds,ENTRY_CREATE, //생성 시 감지
	StandardWatchEventKinds,ENTRY_MODIFY, //변경 시 감지
	StandardWatchEventKinds,ENTRY_DELETE); // 삭제 시 감지

 

  • 위와 같이 등록 후, 변화가 감지 되면 와치 이벤트(WatchEvent)가 발생하고 해당 이벤트 정보를 가진 와치키(WatchKey)를 생성하여 큐(Queue)에 넣어준다.
    • 프로그램은 무한 루프를 돌면서 WatchService의 take()메소드를 호출하여 WatchKey가 큐에 들어올때 까지 대기
while(true){
	WatchKey watchKey = watchService.take();//큐에 WatchKey가 들어올때까지 대기
}

 

  • WatchKey를 얻고 pollEvents() 메소드를 호출해서 WatchEvent 리스트를 얻어낸다.
List<WatchEvent<?>> list = watchKey.pollEvent(); //List인 이유 : 여러 개의 파일이 동시에 변화될 수 있기 때문에.

 

  • 프로그램은 WatchEvent리스트에서 WatchEvent를 하나씩 꺼내어 이벤트의 종류와 Path객체를 얻어내 처리한다.

 

 

 

 

  • 한 번 사용된 WatchKey는 reset()메소드로 초기화해야됨->초기화 성공 시 true, 실패 시 false리턴

 

728x90

댓글