java - walk - oracle random access file
Buffer RandomAccessFile java (4)
RandomAccessFile es bastante lento para el acceso aleatorio a un archivo. A menudo lee acerca de la implementación de una capa almacenada en el búfer, pero no es posible encontrar el código en línea.
Entonces mi pregunta es: ¿querrían ustedes que supieran alguna implementación de código abierto de esta clase compartir un puntero o compartir su propia implementación?
Sería bueno que esta pregunta se convirtiera en una colección de enlaces y códigos útiles sobre este problema, que estoy seguro es compartida por muchos y que SUN nunca ha abordado adecuadamente.
Por favor, no hay referencia a MemoryMapping, ya que los archivos pueden ser mucho más grandes que Integer.MAX_VALUE.
RandomAccessFile es bastante lento para el acceso aleatorio a un archivo. A menudo lee acerca de la implementación de una capa almacenada en el búfer, pero no es posible encontrar el código en línea.
Bueno, es posible encontrar en línea.
Por un lado, el código fuente de JAI en jpeg2000 tiene una implementación, así como una impl aún más no gravada en: http://www.unidata.ucar.edu/software/netcdf-java/
javadocs:
Si está ejecutando en una máquina de 64 bits, entonces los archivos mapeados en memoria son su mejor enfoque. Simplemente asigne todo el archivo en una matriz de búferes de igual tamaño y luego elija un búfer para cada registro según sea necesario (es decir, la respuesta de edalorzo , aunque quiera superponer búferes para que no tenga registros que abarquen los límites).
Si está ejecutando una JVM de 32 bits, entonces está atrapado con RandomAccessFile
. Sin embargo, puede usarlo para leer un byte[]
que contenga su registro completo, luego use un ByteBuffer
para recuperar valores individuales de esa matriz. En el peor de los casos, deberá hacer dos accesos a los archivos: uno para recuperar la posición / tamaño del registro y otro para recuperar el registro.
Sin embargo, tenga en cuenta que puede comenzar a estresar al recolector de basura si crea muchos byte[]
s, y permanecerá vinculado a IO si rebota en todo el archivo.
Puedes hacer un BufferedInputStream desde un RandomAccessFile con un código similar,
RandomAccessFile raf = ...
FileInputStream fis = new FileInputStream(raf.getFD());
BufferedInputStream bis = new BufferedInputStream(fis);
Algunas cosas para notar
- Al cerrar FileInputStream se cerrará RandomAccessFile y viceversa
- RandomAccessFile y FileInputStream apuntan a la misma posición, por lo que la lectura desde FileInputStream hará avanzar el puntero del archivo para el RandomAccessFile, y viceversa
Probablemente la forma en que quieras usar esto sería algo así como
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(...);
Bueno, no veo una razón para no usar java.nio.MappedByteBuffer incluso si los archivos son más grandes que Integer.MAX_VALUE.
Evidentemente, no podrá definir un solo MappedByteBuffer para todo el archivo. Pero podría tener varios MappedByteBuffers accediendo a diferentes regiones del archivo.
La definición de posición y tamaño en FileChannenel.map es de tipo largo, lo que implica que puede proporcionar valores sobre Integer.MAX_VALUE, lo único que debe tener en cuenta es que el tamaño de su búfer no será mayor que Integer.MAX_VALUE .
Por lo tanto, podría definir varios mapas como este:
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);
...
En resumen, el tamaño no puede ser mayor que Integer.MAX_VALUE, pero la posición de inicio puede estar en cualquier lugar de su archivo.
En el libro Java NIO , el autor Ron Hitchens afirma:
El acceso a un archivo a través del mecanismo de asignación de memoria puede ser mucho más eficiente que leer o escribir datos por medios convencionales, incluso cuando se usan canales. No es necesario realizar llamadas explícitas al sistema, lo que puede llevar mucho tiempo. Más importante aún, el sistema de memoria virtual del sistema operativo almacena en caché automáticamente las páginas de memoria. Estas páginas se guardarán en la memoria del sistema y no consumirán espacio del montón de memoria de la JVM.
Una vez que una página de memoria se ha hecho válida (traída desde el disco), se puede volver a acceder a ella a toda velocidad de hardware sin la necesidad de hacer otra llamada al sistema para obtener los datos. Los archivos grandes y estructurados que contienen índices u otras secciones que se referencian o actualizan con frecuencia pueden beneficiarse enormemente de la asignación de memoria. Cuando se combina con el bloqueo de archivos para proteger las secciones críticas y controlar la atomicidad transaccional, se comienza a ver cómo se pueden aprovechar los búferes mapeados en la memoria.
Realmente dudo que encuentres una API de terceros haciendo algo mejor que eso. Quizás pueda encontrar una API escrita sobre esta arquitectura para simplificar el trabajo.
¿No crees que este enfoque debería funcionar para ti?