ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [NIO.2]FileChannel
    JAVA/NIO2 2014. 2. 5. 01:09

    FileChannel은 자바 1.4에서 소개됐지만, SeekableByteChannel 새 인터페이스를 구현하기 위해 최근에 업데이트 되었다.


    SeekableByteChannel은 임의 접근 파일 기능을 제공하며, FileChannel은 파일의 특정 영역을 잠그거나, 고속 접근을 위해 특정 영역을 메모리에 직접 매핑하는 등의 고급 기능을 제공한다.


    다음 예제는 지정된 경로를 읽기/쓰기 할 수 있는 채널을 가져온다.

        public void useFileChannel(){
            Path path = Paths.get("C:/TEMP", "story.txt");
            //읽기 쓰기 파일 채널
            try(FileChannel fileChannel = (FileChannel.open(path, EnumSet.of(StandardOpenOption.READ, StandardOpenOption.WRITE)))){
    
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            //Files.newByteChannel 을 이용한 명시적으로 캐스팅 가능
            try(FileChannel fileChannel = (FileChannel) Files.newByteChannel(path, EnumSet.of(StandardOpenOption.READ, StandardOpenOption.WRITE))){
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    


    채널의 파일 영역을 메모리에 직접 매핑 하기

    FileChannel의 뛰어난 기능 중 하나는 채널의 파일 영역을 메모리에 직접 매핑하는 능력이다.

    FileChannel.map() 매소드 가 위의 기능을 지원하며, 다음과 같이 세가지 인자를 받는다.

    mode 다음 세가지 모드중 하나로 파일 여역을 메모리에 매핑한다.

     - MapMode.READ_ONLY : 읽기전용 매핑, 쓰기를 시도하면 ReadOnlyBufferException 예외가 발생한다.

     - MapMode.READ_WRITE : 읽기/쓰기 매핑, 버퍼의 변경 사항이 파일에 반영되며 같은 파일을 매핑한 다른 프로그램에서 변경사항을 볼 수 있다.

     - MapMode.PRIVATE(쓰기 시 복사 매핑, 버퍼의 변경 사항이 파일에 반영되지 않으며, 다른 프로그램에서 변경 사항을 볼 수 없다.


    postion 매핑된 영역은 파일 안에서 지정된 위치에서 시작한다.(정수)


    size 매핑된 영역의 크기(0 ≤ size ≤ Integer.MAX_VALUE)

    *읽기 전용으로 연 채널만 읽기전용으로 매핑할 수 있으며, 읽기/쓰기 로 연 채널만 읽기/쓰기 비공개로 매핑할 수 있다.


    map() 메소드는 실제로 추출된 영역을 MappedByteBuffer로 반환한다.

    MappedByteBuffer는 ByteBuffer을 확장해 다음 세가지 메소드를 추가 했다.

    force() 버퍼의 변경 사항을 원본 파일에 강제로 반영하다.

    load() 버퍼의 내용을 물리 메모리로 로드한다.

    isLoaded() 버퍼 내용이 물리 메모리에 있는지 확인한다.


    파일 내용을 읽어서 메모리 영역에 매핑 후 출력 하는 예제

      public void readOnlyFileChannel(){
            Path path = Paths.get("C:/TEMP", "story.txt");
            MappedByteBuffer buffer = null;
            try(FileChannel fileChannel = (FileChannel.open(path, EnumSet.of(StandardOpenOption.READ)))){
                buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            if(buffer != null){
                try{
                    Charset charset = Charset.defaultCharset();
                    CharsetDecoder decoder = charset.newDecoder();
                    CharBuffer charBuffer = decoder.decode(buffer);
                    String content = charBuffer.toString();
                    System.out.println(content);
    
                    buffer.clear();
                } catch (CharacterCodingException e) {
                    e.printStackTrace();
                }
            }
    
    

    채널의 파일 잠그기

    파일 잠금은 두명 이상의 사용자가 같은 파일을 동시에 수정하지 못하게 데이터의 일부분이나 파일에 접근하지 못하게 제한하는 메커니즘이다.


    단 아래 사항을 기억해 두어야 한다.

    - 파일 잠금은 자바 가상머신에 대해 잡힌다. 파일 잠금은 같은 가상 머신 안에서 여러 스레드가 한 파일에 대한 접근을 제어하는데 적합하지 않다.

    - 위도는 디렉토리나 다른 구조의 잠금을 처리해주며, 다른 프로세스가 파일을 열었다면 삭제, 이름변경, 쓰기 작업이 실패한다. 따라서 시스템 잠금에 대해 자바 잠금을 만드는 것은 실패하게 된다.

    - 리눅스 커널은 권고 잠금 메커니즘으로 관리한다. 또한, 커널 레벨에서 강제 잠금을 강제로 수행 할 수 있다.


    FileChannel 클래스에서는 파일 잠금을 위해 다음 메소드를 제공한다.

    lock() 원하는 잠금을 가져올때 애플리케이션을 차단

    tryLock() 애플리케이션을 차단하지 않으며 파일이 잠겨 있다면 null을 반환 하거나 예외를 던진다.


    LockApp.java

    public class LockApp {
        public static void main(String[] args){
            Path path = Paths.get("C:/TEMP", "story.txt");
            ByteBuffer buffer = ByteBuffer.wrap("Vamos Rafa!".getBytes());
    
            try(FileChannel fileChannel = (FileChannel.open(path, EnumSet.of(StandardOpenOption.READ, StandardOpenOption.WRITE)))){
                //파일에 잠금을 만들기 위해 파일 채널을 사용한다.
                //이 메소드는 잠금을 가져올 때까지 차단된다.
    
                FileLock lock = fileChannel.lock();
                //차단 없이 잠금을 획득하려 한다.
                //이 메소드는 파일이 이미 잠겨 있다면 null이나 예외를 발생한다.
                try{
                    lock = fileChannel.tryLock();
                }catch(OverlappingFileLockException e){
                    e.printStackTrace();
                }
    
                if(lock.isValid()){
                    System.out.println("Writing to a locked file....");
                    try{
                        Thread.sleep(60000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                    fileChannel.position(0);
                    fileChannel.write(buffer);
    
                    try{
                        Thread.sleep(60000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
                //잠금을 해재한다.
                lock.release();
    
                System.out.println("\nLock released!!");
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    TryApp.java

    public class TryApp {
        public static void main(String[] args){
            Path path = Paths.get("C:/TEMP", "story.txt");
            ByteBuffer buffer = ByteBuffer.wrap("Hai Hanescu !".getBytes());
    
            try(FileChannel fileChannel = (FileChannel.open(path, EnumSet.of(StandardOpenOption.READ, StandardOpenOption.WRITE)))){
                fileChannel.position(0);
                fileChannel.write(buffer);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    


    FIleChannel로 파일 복사 하기

    - 다이렉트바이트 버퍼나 비다이렉트 바이트 버퍼를 이용한 복사

    - FileChannel.transferTo(), FileChannel.transferFrom() 을 이용한 복사

    - FileChannel.map()을 이용한 복사

    *예제는 첨부 파일 참고


    Main.java


    참고 : http://www.javabeat.net/locking-files-using-java/



    'JAVA > NIO2' 카테고리의 다른 글

    [NIO.2]블로킹(BIO) 논블로킹(NIO) 차이점  (0) 2014.03.08
    [NIO.2]NetworkChannel  (0) 2014.02.14
    [NIO.2]ByteBuffer  (0) 2014.02.04
    [NIO.2]SeekableByteChannel  (0) 2014.02.04
    [NIO.2]File Store Attributes  (0) 2013.12.30
Designed by Tistory.