안녕하세요 알통몬입니다. 공감 및 댓글은 포스팅 하는데 아주아주 큰 힘이 됩니다!! 포스팅 내용이 찾아주신 분들께 도움이 되길 바라며 더 깔끔하고 좋은 포스팅을 만들어 나가겠습니다^^
|
파일 비동기 채널 :
FileChannel 의 read() 와 write() 는 파일의 입출력 동안에 블로킹됩니다.
UI 변경이나 이벤트를 처리하는 스레드에서 위 두 개의 메소드를 호출하면 블로킹되는 동안
UI 갱신이나 이벤트 처리가 불가능합니다.
때문에 별도의 작업 스레드를 생성해 위 메소드들을 호출해야 합니다.
그리고 동시에 처리해야 할 파일 수가 많으면 스레드 수도 증가를 하기 때문에 문제가 됩니다.
=> java NIO는 불특정 다수의 파일이나 대용량 파일의 입출력 작업을 위해 비동기 파일 채널을 제공합니다.
AsynchronousFileChannel 의 특징 :
파일의 데이터 입출력을 위해 read() 나 write() 를 호출하면 스레드풀에게 작업 처리 요청을 하고
위 메소드들은 즉시 리턴합니다. 실질적인 입출력 작업 처리는 스레드풀의 작업 스레드가 담당합니다.
작업 스레드가 파일 입출력을 완료하게 되면 콜백 메소드가 자동 호출됩니다.
때문에 작업 완료 후 실행해야 할 메소드가 있다면 콜백 메소드에 작성하면 됩니다.
AsynchronousFileChannel 생성과 닫기
생성은 두 가지 정적 open()을 호출하여 얻을 수 있습니다.
-
AsynchronousFileChannel fileChannel =
AsynchronousFileChannel.open( Path path, OpenOption... options)
위 코드로 생성된 AsynchronousFileChannel 은 내부적으로 생성되는 기본 스레드풀을 이용해
스레드를 관리합니다. 때문에 기본 스레드풀의 최대 스레드 수를 개발자가 지정할 수 없기 때문에
아래 처럼 생성할 수도 있습니다.
-
AsynchronousFileChannel fileChannel =
AsynchronousFileChannel.open(
Path file, // file 의 매개 값은 Path 객체입니다.
Set<? extends OpenOptions> options, // 열기 옵션 값들이 저장될 객체입니다.
ExecutorService service, // 스레드풀인 ExecutorService 객체입니다.
FileAttribute<?>... attrs // 파일 생성 시 파일 속성 값이 될 FileAttribute를 나열합니다.
);
예)
"C:\Temp\file.txt" 파일에 대한 AsynchronousFileChannel 생성 ExecutorService executorService = Excutors.newFixedThreadpool( Runtime.getRuntime().availableProcessors() // CPU 코어 수 리턴합니다. ); AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open( Paths.get("C:\Temp\file.txt"), EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.WRITE), // 매개값으로 나열된 열거 상수를 Set 객체에 리턴합니다. executorService ); AsynchronousFileChannel 을 더 이상 사용하지 않을 경우 close()메서드 호출해서 닫아줍니다. fileChannel.close(); |
파일 읽기와 파일 쓰기
AsynchronousFileChannel 이 생성되었다면 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 매개 값은 콜백 메소드로 전달할 첨부 객체 입니다. => 콜백 메소드에서 결과 값 이외에
추가적인 정보를 얻고자 할 때 사용하는 객체로, 첨부 객체가 없을 경우는 null을 대입하면 됩니다.
handler 매개 값은 CompletionHandler< Integer, A>를 저장하는데
Integer 는 입출력 작업의 결과 타입으로 read() 나 write() 가 읽거나 쓴 바이트 수 입니다.
A는 첨부 객체 타입으로 CompletionHandler 구현 객체를 작성할 때 임의로 지정 가능하며
첨부 객체가 필요 없다면 A = Void를 지정하면 됩니다.
CompletionHandler<Integer, A> 구현 객체는 비동기 작업이 정상적으로 완료된 경우와
예외 발생으로 실패한 경우에 자동으로 콜백되는 두 메소드를 가지고 있어야 합니다.
completed() 의 result 매개 값은 작업 결과가 대입되는데, read() 와 write() 작업 결과는 읽거나 쓴
바이트 수입니다.
attachment 매개 값은 read() 와 write() 호출 시에 제공된 첨부 객체입니다.
failed()의 exc 매개 값은 작업 처리 도중 발생한 예외입니다.
** 콜백 메소드를 실행하는 스레드는 read() 나 write() 를 호출한 스레드가 아니고, 스레드풀의
작업 스레드입니다.
=> javaFX 애플리케이션의 경우에 UI 성성 및 변경 작업을 이 메소드에서 직접할 수 없고
Platform.runLater()를 이용해야 합니다.
ex) CompletionHandler 구현 클래스 작성 방법 new CompletionHandler<Integer, A>() { @Override public void completed(Integer result, A attachment){ ... } @Override public void failed(Throwable exc, A attachment) { ... } }; |
예제)
import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousFileChannel; import java.nio.channels.CompletionHandler; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.EnumSet; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Example { public static void main(String[] args) throws Exception { //스레드풀 생성 ExecutorService executorService = Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() //CPU 코어 개수 리턴 );
for(int i=0; i<10; i++) { Path path = Paths.get("C:/Temp/file" + i + ".txt"); Files.createDirectories(path.getParent());
//비동기 파일 채널 생성 AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open( path, EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.WRITE), executorService );
Charset charset = Charset.defaultCharset(); ByteBuffer byteBuffer = charset.encode("안녕~");
//첨부 객체 생성 class Attachment { Path path; AsynchronousFileChannel fileChannel; } Attachment attachment = new Attachment(); attachment.path = path; attachment.fileChannel = fileChannel;
//CompletionHandler 객체 생성 CompletionHandler<Integer, Attachment> completionHandler = new CompletionHandler<Integer, Attachment>() { @Override public void completed(Integer result, Attachment attachment) { System.out.println(attachment.path.getFileName() + " : " + result + " bytes written : " + Thread.currentThread().getName()); try { attachment.fileChannel.close(); } catch (IOException e) {} } @Override public void failed(Throwable exc, Attachment attachment) { exc.printStackTrace(); try { attachment.fileChannel.close(); } catch (IOException e) {} } };
fileChannel.write(byteBuffer, 0, attachment, completionHandler); }
//스레드풀 종료 executorService.shutdown(); } } |
이상입니다.
다음 포스팅에서는 TCP 블로킹 채널에 대해 공부하겠습니다.
'자바' 카테고리의 다른 글
자바 NIO TCP 블로킹 채널로 채팅 서버 구현하기 (0) | 2017.04.19 |
---|---|
자바 NIO TCP 블로킹 채널 (0) | 2017.04.18 |
자바 NIO 파일 채널 - FileChannel의 생성과 닫기, 파일 쓰기와 읽기, 파일 복사 (1) | 2017.04.16 |
자바 NIO 버퍼 메소드 - 공통, 데이터를 읽고 저장하는, 버퍼 예외 종류 (0) | 2017.04.16 |
자바 NIO 버퍼 - Buffer 의 종류, Buffer 생성 버퍼 생성, 버퍼 위치 속성 (0) | 2017.04.16 |