[Java] 버퍼링 된 RandomAccessFile 자바


Answers

글쎄, 파일이 Integer.MAX_VALUE보다 큰 경우에도 java.nio.MappedByteBuffer를 사용하지 않을 이유가 없다.

분명히 전체 파일에 대해 단일 MappedByteBuffer를 정의 할 수는 없습니다. 그러나 여러 MappedByteBuffers가 파일의 다른 영역에 액세스 할 수 있습니다.

FileChannenel.map의 위치 및 크기의 정의는 long 유형이며, 이는 Integer.MAX_VALUE에 대한 값을 제공 할 수 있음을 의미 합니다. 버퍼 크기 가 Integer.MAX_VALUE보다 크지 않도록주의해야합니다 .

따라서 다음과 같이 여러 맵을 정의 할 수 있습니다.

buffer[0] = fileChannel.map(FileChannel.MapMode.READ_WRITE,0,2147483647L);
buffer[1] = fileChannel.map(FileChannel.MapMode.READ_WRITE,2147483647L, Integer.MAX_VALUE);
buffer[2] = fileChannel.map(FileChannel.MapMode.READ_WRITE, 4294967294L, Integer.MAX_VALUE);
...

요약하면 크기는 Integer.MAX_VALUE보다 클 수 없지만 시작 위치는 파일의 어느 위치 에나있을 수 있습니다.

Book Java NIO 에서 Ron Hitchens는 다음과 같이 말합니다.

메모리 매핑 메커니즘을 통해 파일에 액세스하는 것은 채널을 사용하는 경우에도 기존 방법으로 데이터를 읽거나 쓰는 것보다 훨씬 효율적입니다. 명시 적 시스템 호출을 수행 할 필요가 없으므로 시간이 오래 걸릴 수 있습니다. 더 중요한 것은 운영 체제의 가상 메모리 시스템이 자동으로 메모리 페이지를 캐시한다는 것입니다. 이러한 페이지는 시스템 메모리를 사용하여 캐시되며 JVM 메모리 힙의 공간을 소비하지 않습니다.

일단 메모리 페이지가 유효하게되면 (디스크에서 가져온), 데이터를 얻기 위해 다른 시스템 호출을하지 않고도 전체 하드웨어 속도로 다시 액세스 할 수 있습니다. 자주 참조되거나 업데이트되는 색인이나 기타 섹션을 포함하는 대형 구조 파일은 메모리 매핑을 통해 엄청난 이익을 얻을 수 있습니다. 중요한 섹션을 보호하고 트랜잭션의 원 자성을 제어하기 위해 파일 잠금과 결합되면 메모리 매핑 된 버퍼를 잘 활용할 수있는 방법을 살펴볼 수 있습니다.

나는 당신이 써드 파티 API가 그것보다 더 나은 것을 발견하게 될지 의심 스럽다. 아마도이 아키텍처 위에 작성된 API를 사용하여 작업을 단순화 할 수 있습니다.

이 접근법이 당신을 위해 일해야한다고 생각하지 않습니까?

Question

RandomAccessFile은 파일에 무작위로 액세스하는 경우 매우 느립니다. 그 위에 버퍼링 된 레이어를 구현하는 방법에 대해 자주 읽지 만,이를 수행하는 코드는 온라인에서 찾을 수 없습니다.

그래서 내 질문은 : 당신이 누군지이 클래스의 모든 opensource 구현을 알고 포인터를 공유하거나 자신의 구현을 공유?

이 질문이이 문제에 대한 유용한 링크와 코드의 모음으로 밝혀지면 좋을 것입니다. 물론이 문제는 많은 사람들이 공유하고 있으며 SUN이 제대로 해결하지 못했습니다.

파일이 Integer.MAX_VALUE보다 크게 될 수 있으므로 MemoryMapping에 대한 참조가 없습니다.




64 비트 컴퓨터에서 실행중인 경우 메모리 매핑 파일이 가장 좋은 방법입니다. 단순히 전체 파일을 동일한 크기의 버퍼 배열로 매핑 한 다음 필요에 따라 각 레코드에 대한 버퍼를 선택하십시오 (예 : edalorzo 의 대답, 경계를 넘는 레코드가 없도록 겹치는 버퍼가 필요함 ).

32 비트 JVM에서 실행중인 경우에는 RandomAccessFile 을 사용해야합니다. 그러나 전체 레코드가 들어있는 byte[] 를 읽은 다음 ByteBuffer 를 사용하여 해당 배열에서 개별 값을 검색 할 수 있습니다. 최악의 경우, 레코드의 위치 / 크기를 검색하는 레코드와 레코드 자체를 검색하는 레코드의 두 가지 액세스를 만들어야합니다.

그러나 byte[] 많이 만들면 가비지 수집기에 스트레스를주기 시작할 수 있으며 파일 전체를 튀어 오르게하면 IO 바인딩 상태가 유지됩니다.




RandomAccessFile에서 BufferedInputStream을 다음과 같은 코드로 만들 수 있습니다.

 RandomAccessFile raf = ...
 FileInputStream fis = new FileInputStream(raf.getFD());
 BufferedInputStream bis = new BufferedInputStream(fis);

몇 가지 유의 사항

  1. FileInputStream을 닫으면 RandomAccessFile이 닫히고 그 반대의 경우도 마찬가지입니다.
  2. RandomAccessFile과 FileInputStream은 같은 위치를 가리키고 있으므로 FileInputStream을 읽으면 RandomAccessFile에 대한 파일 포인터가 앞으로 이동하고 그 반대의 경우도 마찬가지입니다.

아마 당신이 이것을 사용하길 원하는 방식 일 겁니다.

RandomAccessFile raf = ...
FileInputStream fis = new FileInputStream(raf.getFD());
BufferedInputStream bis = new BufferedInputStream(fis);

//do some reads with buffer
bis.read(...);
bis.read(...);

//seek to a a different section of the file, so discard the previous buffer
raf.seek(...);
bis = new BufferedInputStream(fis);
bis.read(...);
bis.read(...);



RandomAccessFile은 파일에 무작위로 액세스하는 경우 매우 느립니다. 그 위에 버퍼링 된 레이어를 구현하는 방법에 대해 자주 읽지 만,이를 수행하는 코드는 온라인에서 찾을 수 없습니다.

글쎄, 온라인으로 찾을 수 있습니다.
하나 들어, jpeg2000에서 JAI 소스 코드는 다음과 같은 구현을 포함하고 있습니다 : http://www.unidata.ucar.edu/software/netcdf-java/

javadocs :

http://www.unidata.ucar.edu/software/thredds/v4.3/netcdf-java/v4.0/javadoc/ucar/unidata/io/RandomAccessFile.html