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

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

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

1. 파일 채널

  • java.nio.channels.FileChannel을 이용하면 파일 읽기와 쓰기를 할 수 있다.
  • FileChannel은 동기화 처리가 되어 있기 때문에 멀티 스레드 환경에서 안전하다.

 

 

FileChannel 생성과 닫기

  • FileChannel은 정적 메소드인 open()을 호출해서 채널을 열거나, IO의 FileInputStream,FileOutputStream의 getChannel()메소드 호출
FileChannel fileChannel = FileChannal.open(Path path, OpenOption ... options);

 

  • FileChannel의 open()메소드의 첫번째 매개값 : Path객체로 생성된 파일의 경로
  • FileChannel의 open()메소드의 두번째 매개값 : 열기 옵션값으로 StandardOpenOption의 열거 상수를 나열해준다.

 

StandardOpenOption의 열거 상수

 

 

ex. C:\Temp\file.txt 파일을 생성하고, 쓰고 싶을 때

FileChannel fileChannel = FileChannel.open(
     Paths.get("C:/Temp/file.txt");
     StandardOpenOption.CREATE_NEW,
     StandardOpenOption.WRITE);

 

  • FileChannel을 더 이상 사용하지 않을 경우 close()메소드를 호출한다.
fileChannel.close();

 

파일 쓰기와 읽기

 

파일 쓰기

  • 파일에 바이트를 쓰려면 FileChannel의 write() 메소드를 호출하고 매개값으로 ByteBuffer객체를 주면 된다.
    • 파일이 쓰여지는 바이트는 ByteBuffer의 position부터 limit까지이다.(position = 0, limit=capacity 경우 모든 바이트 쓰기)
  • write()메소드의 리턴값은 ByteBuffer에서 파일로 쓰여진 바이트 수
int bytesCount = fileChannel.write(ByteBuffer src);

 

ex.

 

파일 읽기

  • 파일로부터 읽기 위해서 FileChannel의 read()메소드를 호출하고, 매개값으로 ByteBuffer객체를 주면 된다.
    • ByteBuffer의 position부터 저장된다.
  • read()메소드의 리턴값은 파일에서 ByteBuffer로 읽혀진 바이트 수
    • 최대 바이트수는 ByteBuffer의 capacity까지므로 리턴되는 최대값은 capacity가 됨, 더 이상 읽을 바이트없으면 -1 리턴
int bytesCount = fileChannel.read(ByteBuffer dst);

 

 

ex.

 

 

※ clear() 는 버퍼 내에 자료를 지우는 것이 아니고 위치 속성을 초기화 한다.

 

파일 복사

 

  • 위와 같이 버퍼에 읽고, 해당 버퍼에서 쓰기를 통해서 복사도 가능
  • 단순한 파일을 복사할 목적이면 NIO의 Files클래스의 copy()메소드를 사용하는 것이 편리
Path targetPatg = Files.copy(Path source, Path target, CopyOption ... options);

 

  • copy()메소드 첫번째 매개값 : 복사할 원본 파일
  • copy()메소드 두번째 매개값 : 복사한 원본 파일을 저장할 위치
  • copy()메소드 세번쨰 매개값 : StandardCopyOption열거 상수를 목적에 맞게 나열하면 된다.

 

열거 상수                                     설명

PEPLACE_EXISTING                타겟 파일이 존재하면 대체한다.

COPY_ATTRIBUTES                 파일의 속성까지도 복사한다.

NOFOLLOW_LINKS                   링크 파일일 경우 링크 파일만 복사하고 링크된 파일은 복사하지 않는다.

 

 

비동기 파일 채널

  • 위의 FileChannel의 read()와 write()메소드는 파일 입출력 작업 동안 블로킹된다.
    • UI 및 이벤트를 처리하는 스레드에서 이 메소드 호출하면 UI 갱신이나 이벤트 처리 불가, 별로 스레드로 처리해야함
    • 동시에 처리할 파일 수가 많아지면 스레드 수도 증가해야하므로 문제가 될 수 있다.

 

  • 자바 NIO는 불특정 다수의 파일 및 대용량 파일의 입출력 작업을 위해서 비동기 파일 채널(AsychronousFileChannel) 제공

 

비동기 파일 채널 - AsychronousFileChannel

  • 파일의 데이터 입출력을 위해 read()와 write()메소드를 호출하면 스레드풀에게 작업 처리를 요청하고 이 메소드들을 즉시 리턴시킴
  • 스레드 풀의 작업 스레드가 파일 입출력을 완료하게 되면 콜백(callback) 메소드가 자동 호출되기 떄문에 작업완료 후 실행해야 할 코드가 있다면 콜백 메소드에 작성한다.

 

  • 위와 같은 순서로 작업을 처리한다.

 

AsychronousFileChannel 생성과 닫기

생성 

  • AsychronousFileChannel은 두가지 정적 메소드인 open()을 호출해서 얻을 수 있다.
//첫번째 방법 - 특징 : 내부적으로 생성되는 기본 스레드풀을 이용해서 스레드 관리
AsychronousFileChannel fileChannel = AsychronousFileChannel.open(
       Path file,
       OpenOption ... options
);

//두번째 방법 - 특징 : 스레드풀 설정 가능
AsychronousFileChannel fileChannel = AsychronousFileChannel .open(
        Path file,
        Set<?extends OpenOption> options,
        ExecutorService executor,  // 스레드풀인 ExecutorService 객체
        FileAttribute<?>... atrrs  // 파일 생성 시 파일 속성값이 될 FileAttribute를 나열
);
  • file 매개값은 파일의 Path객체, options매개값은 열거 옵션값들이 저장된 Set객체 - EnumSet.of(OpenOption...options)

 

ex.

ExecutorService executorService = Executor.newFixedThreadPool(
    Runtime.getRuntime().availableProcessors()
);

AsychronousFileChannel fileChannel = AsychronousFileChannel.open(
      Paths.get("파일경로"),
      EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.WRITE),
      executorService
);

 

 

닫기

  • AsychronousFileChannel을 더 이상 사용하지 않을 경우 close()메소드를 호출

 

fileChannel.close();

 

파일 읽기와 쓰기

  • AsychronousFileChannel이 생성되었으면 read(), write()메소드를 이용하여 입출력 가능
read(ByteBuffer dst, long position, A attachment, CompletionHandler<Integer, A> handler); 
write(ByteBuffer src, long position, A attachment, CompletionHandler<Integer, A> handler);
  • 이 메소드 호출 시 즉시 리턴되고, 스레드풀의 스레드가 입출력 작업 진행
  • dst와 src 매개값은 읽거나 쓰기 위한 ByteBuffer 지정, position 매개값은 파일에서 읽을 위치이거나 쓸 위치
  • attachment 매개값은 콜백 메소드로 전달할 첨부 객체, 첨부 객체는 콜백 메소드에서 결과값 외에 추가적인 정보를 얻고 싶을 때 사용
  • handler 매개값은 CompletionHandler<Integer, A> 구현 객체를 지정한다, Integer는 입출력 작업의 결과 타입으로, read()와 write()가 읽거나 쓴 바이트수, A는 첨부 객체 타입으로 개발자가 CompletionHandler 구현 객체를 작업 시 임의로 지정 가능하다.(Void 가능)

 

  • CompletionHandler 구현 객체는 비동기 작업이 정상적으로 완료될 경우와 예외 발생으로 실패된 경우에 자동 콜백되는 메소드 가짐

 

  • completed() 메소드 : result 매개값은 작업 결과가 대입되는데, read()와 write()작업 결과는 읽거나 쓴 바이트 수, attachment 매개값은 read()와 write() 호출 시 제공되는 첨부 객체
  • failed()메소드 : exc매개값은 작업 처리 도중 발생한 예외

 

※ 주목할 점 : 콜백 메소드를 실행하는 스레드는 read()나 write()를 호출한 스레드가 아니고, 스레드풀의 작업 스레드이다.

  • 그렇기 때문에 JavaFX애플리케이션일 경우 UI생성 및 변경 작업을 이 메소드에서 직접할 수 없고 Platform.runLater()이용해야함

 

ex. 파일 비동기 채널 쓰기

ex. 파일 비동기 채널 읽기

 

 

 

  • write()메소드는 즉시 리턴되기때문에 같은 쓰레드상에서 AsynchronousFileChannel를 닫아버리면 작업 스레드가 작업을 완료하기 전에 채널을 닫아 버릴 수 있다.
    • 그러므로 completed()와 failed()메소드에서 AsynchronousFileChannel의 close()를 호출한다. 

 

728x90

댓글