Буферизованный RandomAccessFile Java - PullRequest
19 голосов
/ 10 апреля 2011

RandomAccessFile довольно медленно для произвольного доступа к файлу. Вы часто читаете о реализации над ним буферизованного слоя, но код, делающий это, невозможно найти в Интернете.

Итак, мой вопрос: вы, ребята, которые знаете какую-либо реализацию этого класса с открытым исходным кодом, поделитесь указателем или поделитесь своей собственной реализацией?

Было бы неплохо, если бы этот вопрос оказался набором полезных ссылок и кода по этой проблеме, который, я уверен, распространен многими и никогда не был должным образом рассмотрен SUN.

Пожалуйста, не упоминайте MemoryMapping, поскольку файлы могут быть больше, чем Integer.MAX_VALUE.

Ответы [ 4 ]

12 голосов
/ 11 апреля 2011

Ну, я не вижу причин не использовать java.nio.MappedByteBuffer, даже если файлы больше Integer.MAX_VALUE.

Очевидно, вам не разрешат определять один 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, но начальная позиция может быть где угодно в вашем файле.

В Книге Java NIO автор Рон Хитченс утверждает:

Доступ к файлу черезМеханизм отображения памяти может быть гораздо более эффективным, чем чтение или запись данных обычными средствами, даже при использовании каналов.Не нужно делать явных системных вызовов, что может занять много времени.Что еще более важно, система виртуальной памяти операционной системы автоматически кэширует страницы памяти.Эти страницы будут кэшироваться с использованием системной памяти и не будут занимать пространство из кучи памяти JVM.

Как только страница памяти станет действительной (введена с диска), к ней можно будет снова обращаться с полной аппаратной скоростью безнужно сделать еще один системный вызов, чтобы получить данные.Большие структурированные файлы, содержащие индексы или другие разделы, на которые часто ссылаются или которые часто обновляются, могут значительно выиграть от сопоставления памяти.В сочетании с блокировкой файлов для защиты критических секций и управления атомарностью транзакций вы начинаете понимать, как можно эффективно использовать буферы отображения памяти.

Я действительно сомневаюсь, что вы найдете сторонний APIделать что-то лучше, чем это.Возможно, вы найдете API, написанный поверх этой архитектуры, чтобы упростить работу.

Не думаете ли вы, что этот подход должен работать для вас?

11 голосов
/ 14 декабря 2013

Вы можете создать BufferedInputStream из файла RandomAccessFile с кодом наподобие

 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(...);
2 голосов
/ 24 января 2012

RandomAccessFile довольно медленно для произвольного доступа к файлу. Вы часто читаете о реализации над ним буферизованного слоя, но код, делающий это, невозможно найти в Интернете.

Ну, это можно найти в Интернете.
С одной стороны, исходный код JAI в jpeg2000 имеет реализацию, а также еще более не обремененный импл в: 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

1 голос
/ 11 апреля 2011

Если вы работаете на 64-битной машине, то отображаемые в памяти файлы - ваш лучший подход.Просто отобразите весь файл в массив одинаковых по размеру буферов, затем выберите буфер для каждой записи по мере необходимости (т. Е. Ответ edalorzo , однако вам нужны перекрывающиеся буферы, чтобы у вас не было записейграницы этого диапазона).

Если вы работаете на 32-битной JVM, значит, вы застряли с RandomAccessFile.Однако вы можете использовать его для чтения byte[], который содержит всю вашу запись, а затем используйте ByteBuffer для извлечения отдельных значений из этого массива.В худшем случае вам нужно сделать два доступа к файлу: один для получения позиции / размера записи, а другой - для самой записи.

Однако имейте в виду, что вы можете начать использовать сборщик мусора, еслисоздайте много byte[] с, и вы останетесь привязанными к IO, если отскок по всему файлу.

...