자바 메모리 맵 큰 파일 쉽게 처리

머리말
메모리 맵 파일(Memory-mapped File)은 가상 메모 리 를 한 파일 에 매 핑 하여 프로그램 처리 파일 을 주 메모리 에 접근 하 는 것 과 같 게 하 는 것 을 말한다.
가상 메모리(물리 적 메모리 가 아 닌 것 이 분명 합 니 다)는 컴퓨터 시스템 메모리 관리 기술 입 니 다.요술 을 부 린 것 처럼 프로그램 은 연속 적 으로 사용 가능 한 메모 리 를 가지 고 있다 고 생각 합 니 다.실제로 여러 개의 물리 적 메모리 로 구 분 된 조각 이 고 일 부 는 외부 디스크 메모리 에 잠시 저장 되 어 필요 할 때 데이터 교환 을 합 니 다.
메모리 맵 파일 의 주요 용 도 는 I/O 성능 을 증가 시 키 는 것 입 니 다.특히 큰 파일 을 대상 으로 합 니 다.작은 파일 에 대해 서 는 메모리 맵 파일 이 오히려 조각 공간의 낭 비 를 초래 할 수 있 습 니 다.메모리 맵 은 항상 페이지 경 계 를 맞 춰 야 하기 때 문 입 니 다.최소 단 위 는 4 KiB 이 고 5 KiB 의 파일 은 8 KiB 메모 리 를 차지 하 며 3 KiB 메모 리 를 낭비 합 니 다.
java.nio 패 키 지 는 메모리 매 핑 을 매우 간단하게 만 들 었 습 니 다.그 중의 핵심 클래스 는 MappedByteBuffer 라 고 하 는데,글자 의 뜻 은 매 핑 된 바이트 버퍼 입 니 다.
01、MappedByteBuffer 로 파일 읽 기
현재 cmower.txt 라 는 파일 이 있다 고 가정 하면 그 내용 은:
침묵 왕 2,재 미 있 는 프로그래머
PS:아,왕 할머니 가 참 외 를 팔 아 자화자찬 하 는 버릇 을 고 칠 수가 없어 요.글 이 도 둑 맞 아서 무서워 요.
이 파일 은/resource 디 렉 터 리 에 놓 여 있 습 니 다.아래 방법 으로 가 져 올 수 있 습 니 다.

ClassLoader classLoader = Cmower.class.getClassLoader();
Path path = Paths.get(classLoader.getResource("cmower.txt").getPath());
Path 는 디 렉 터 리 를 표시 할 수도 있 고 파일 을 표시 할 수도 있 습 니 다.File 처럼-물론 Path 는 File 을 대체 하 는 데 사 용 됩 니 다.
그리고 파일 에서 채널(채널,디스크 파일 에 대한 추상)을 가 져 옵 니 다.

FileChannel fileChannel = FileChannel.open(path);
이 어 FileChannel 류 의 map 방법 을 사용 하여 channel 에서 MappedByteBuffer 를 가 져 왔 습 니 다.이러한 확장 은 ByteBuffer―메모리 맵 파일 의 기본 적 인 조작 방법 을 제공 합 니 다.

MappedByteBuffer mappedByteBuffer = fileChannel.map(mode, position, size);
맵 방법의 세 가지 인 자 를 살짝 설명해 주세요.
1)mode 는 파일 맵 모드 로 세 가지 로 나 뉜 다.
  • MapMode.READ_ONLY(읽 기 전용)버퍼 를 수정 하려 는 모든 작업 은 ReadOnly BufferException 이상 을 가 져 옵 니 다.
  • MapMode.READ_WRITE(읽 기/쓰기),버퍼 에 대한 변경 사항 은 언제든지 파일 에 기 록 됩 니 다.주의해 야 할 것 은 같은 파일 을 매 핑 하 는 다른 프로그램 들 이 이러한 수정 사항 을 즉시 볼 수 없 을 수도 있 고 여러 프로그램 이 동시에 파일 매 핑 을 하 는 행 위 는 운영 체제 에 의존 할 수도 있다 는 것 이다.
  • MapMode.PRIVATE(개인)는 버퍼 에 대한 변경 사항 을 이 파일 에 기록 하지 않 습 니 다.모든 변경 사항 은 이 버퍼 에 개인 적 입 니 다.
  • 2)position 는 파일 맵 의 시작 위치 입 니 다.
    3)size 는 매 핑 할 영역의 크기 이 며,반드시 마이너스 여야 하 며,Integer.MAX 보다 크 면 안 됩 니 다.VALUE。
    메모리 버퍼 에 파일 을 비 추 면 CharBuffer 에 데 이 터 를 읽 고 인쇄 할 수 있 습 니 다.구체 적 인 코드 예 는 다음 과 같다.
    
    CharBuffer charBuffer = null;
    ClassLoader classLoader = Cmower.class.getClassLoader();
    Path path = Paths.get(classLoader.getResource("cmower.txt").getPath());
    try (FileChannel fileChannel = FileChannel.open(path)) {
     MappedByteBuffer mappedByteBuffer = fileChannel.map(MapMode.READ_ONLY, 0, fileChannel.size());
    
     if (mappedByteBuffer != null) {
      charBuffer = Charset.forName("UTF-8").decode(mappedByteBuffer);
     }
    
     System.out.println(charBuffer.toString());
    } catch (IOException e) {
     e.printStackTrace();
    }
    decode()방법의 매개 변 수 는 Mapped Byte Buffer 이기 때문에 디스크 가 아 닌 메모리 에서 읽 은 파일 내용 이기 때문에 속도 가 매우 빠 를 것 입 니 다.
    02、MappedByteBuffer 로 파일 쓰기
    지금 아래 내용 을 파일 에 쓰 려 면 cmower 1.txt 라 고 가정 합 니 다.
    침묵 왕 2,저자
    이 파일 은 아직 만 들 지 않 았 습 니 다.프로젝트 의 classpath 디 렉 터 리 에 놓 을 계획 입 니 다.
    
    Path path = Paths.get("cmower1.txt");
    구체 적 인 위 치 는 다음 그림 과 같다.

    그리고 파일 을 만 드 는 채널 입 니 다.
    
    FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ, StandardOpenOption.WRITE,
        StandardOpenOption.TRUNCATE_EXISTING)
    여전히 사용 하 는 open 방법 은 3 개의 인 자 를 추 가 했 습 니 다.앞의 2 개 는 이해 하기 쉽 고 파일 읽 기(READ),쓰기(WRITE)를 표시 합 니 다.세 번 째 매개 변수 TRUNCATEEXISTING 은 파일 이 이미 존재 하고 파일 이 열 려 있 으 면 WRITE 작업 을 하려 면 길이 가 0 으로 잘 린 다 는 뜻 이다.
    이 어 FileChannel 류 의 map 방법 을 사용 하여 channel 에서 MappedByteBuffer 를 가 져 옵 니 다.
    
     MappedByteBuffer mappedByteBuffer = fileChannel.map(MapMode.READ_WRITE, 0, 1024);
    이번에 우 리 는 모드 를 MapMode.READ 로 조정 했다.WRITE,파일 크기 를 1024,즉 1KB 크기 로 지정 합 니 다.그리고 MappedByteBuffer 의 put()방법 으로 CharBuffer 의 내용 을 파일 에 저장 합 니 다.구체 적 인 코드 예 는 다음 과 같다.
    
    CharBuffer charBuffer = CharBuffer.wrap("    ,《Web        》  ");
    Path path = Paths.get("cmower1.txt");
    try (FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ, StandardOpenOption.WRITE,
      StandardOpenOption.TRUNCATE_EXISTING)) {
     MappedByteBuffer mappedByteBuffer = fileChannel.map(MapMode.READ_WRITE, 0, 1024);
    
     if (mappedByteBuffer != null) {
      mappedByteBuffer.put(Charset.forName("UTF-8").encode(charBuffer));
     }
    
    } catch (IOException e) {
     e.printStackTrace();
    }
    cmower 1.txt 를 열 어 내용 을 확인 하고 예상 한 내용 이 기록 되 었 는 지 확인 할 수 있 습 니 다.
    03.Mappedbytebuffer 의 아 쉬 움
    자바 에서 Mapped Byte Buffer 를 사용 하 는 것 은 매우 번 거 롭 고 고통스러운 일이 라 고 합 니 다.주로 다음 과 같은 표현 이 있 습 니 다.
    1)1 회 맵 의 크기 는 1.5G 정도 로 제한 하 는 것 이 좋 으 며,중복 맵 은 가상 메모리 회수 와 재배 치 압력 을 증가 시 킵 니 다.파일 크기 가 확실 하지 않 으 면 그다지 우호 적 이지 않다 는 것 이다.
    2)가상 메모 리 는 운영 체제 에서 디스크 를 언제 새로 고 칠 지 결정 합 니 다.이 시간 은 프로그램 에 의 해 제어 되 기 쉽 지 않 습 니 다.
    3)Mapped Byte Buffer 의 회수 방식 은 비교적 기괴 하 다.
    다시 한 번 강조 하지만 이 세 가지 설 은 모두 내 가 일시 적 으로 능력 에 한계 가 있 고 이런 설의 정확성 을 확정 할 수 없다 는 것 이 라 고 하 는데 매우 유감스럽다.
    04.파일 작업 의 처리 시간 비교
    어이,친구 야,이상 의 내용 을 다 읽 은 후에 나 는 네가 메모리 맵 파일 에 대해 대충 알 게 되 었 을 것 이 라 고 생각한다.하지만 책임 있 는 프로그래머 라면 메모리 맵 파일 의 읽 기 속도 가 얼마나 빠 른 지 알 고 싶 을 것 이 라 고 믿 습 니 다.
    결론 을 내리 기 위해 저 는 다른 세 명의 경기 선 수 를 불 렀 습 니 다.InputStream(일반 입력 흐름),Buffered InputStream(버퍼 가 있 는 입력 흐름),RandomAccessFile(랜 덤 액세스 파일).
    읽 는 대상 은 카 리 브 해적 4 의 파도.mkv 로 크기 는 1.71G 이다.
    1)일반 입력 흐름
    
    public static void inputStream(Path filename) {
     try (InputStream is = Files.newInputStream(filename)) {
      int c;
      while((c = is.read()) != -1) {
      }
     } catch (IOException e) {
      e.printStackTrace();
     }
    }
    2)버퍼 가 있 는 입력 흐름
    
    public static void bufferedInputStream(Path filename) {
     try (InputStream is = new BufferedInputStream(Files.newInputStream(filename))) {
      int c;
      while((c = is.read()) != -1) {
      }
     } catch (IOException e) {
      e.printStackTrace();
     }
    }
    3)무 작위 접근 파일
    
    public static void randomAccessFile(Path filename) {
     try (RandomAccessFile randomAccessFile = new RandomAccessFile(filename.toFile(), "r")) {
      for (long i = 0; i < randomAccessFile.length(); i++) {
       randomAccessFile.seek(i);
      }
     } catch (IOException e) {
      e.printStackTrace();
     }
    }
    4)메모리 맵 파일
    
    public static void mappedFile(Path filename) {
     try (FileChannel fileChannel = FileChannel.open(filename)) {
      long size = fileChannel.size();
      MappedByteBuffer mappedByteBuffer = fileChannel.map(MapMode.READ_ONLY, 0, size);
      for (int i = 0; i < size; i++) {
       mappedByteBuffer.get(i);
      }
     } catch (IOException e) {
      e.printStackTrace();
     }
    }
    테스트 프로그램 도 간단 합 니 다.대체적으로 다음 과 같 습 니 다.
    
    long start = System.currentTimeMillis();
    bufferedInputStream(Paths.get("jialebi.mkv"));
    long end = System.currentTimeMillis();
    System.out.println(end-start);
    네 선수 의 결 과 는 다음 과 같다.
    방법.
    시간.
    일반 입력 흐름
    거북 속,인내심 없 이 결 과 를 기다리다.
    무 작위 접근 파일
    거북 속,인내심 없 이 기 다 려 라.
    버퍼 가 있 는 입력 흐름
    29966
    메모리 맵 파일
    914
    보통 입력 흐름 과 무 작위 접근 파일 이 느 려 서 정말 거북이 속도 입 니 다.저 는 인내심 을 가지 고 결 과 를 기다 리 지 않 았 습 니 다.버퍼 가 있 는 입력 흐름 은 괜 찮 지만 메모리 맵 파일 보다 훨씬 손 색 이 있 습 니 다.이 를 통 해 얻 은 결론 은 메모리 맵 파일,G 큰 파일 을 쉽게 처리 한 다 는 것 이다.
    05 마지막
    이 글 은 자바 의 메모리 맵 파일 을 소개 하 는데 Mapped ByteBuffer 는 영혼 으로 로켓 처럼 읽 는 속도 가 빠르다.또한 모든 예제 와 코드 세 션GitHub 에서 찾기-Maven 프로젝트 이기 때문에 가 져 오고 실행 하기 쉽다.
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기