2012-02-01 11 views
10

¿cuál es la forma más rápida de leer archivos relativamente grandes con los métodos de E/S de Java? Mi solución actual usa el guardado BufferedInputStream en una matriz de bytes con 1024 bytes asignados. Cada búfer se guarda en un ArrayList para su uso posterior. Todo el proceso se llama a través de un hilo separado (interfaz invocable).La forma más rápida de leer archivos de bytes relativamente grandes en Java

No muy rápido.

ArrayList<byte[]> outputArr = new ArrayList<byte[]>();  
    try { 
     BufferedInputStream reader = new BufferedInputStream(new FileInputStream (dir+filename)); 

     byte[] buffer = new byte[LIMIT]; // == 1024 
      int i = 0; 
      while (reader.available() != 0) { 
       reader.read(buffer); 
       i++; 
       if (i <= LIMIT){ 
        outputArr.add(buffer); 
        i = 0; 
        buffer = null; 
        buffer = new byte[LIMIT]; 
       } 
       else continue;    
      } 

     System.out.println("FileReader-Elements: "+outputArr.size()+" w. "+buffer.length+" byte each."); 
+0

Eche un vistazo a las bibliotecas de Apache Commons para obtener más opciones. Y para determinar la velocidad, eche un vistazo al libro de Java Performance Tuning de O'Reilly. – therobyouknow

+5

Actualmente está ignorando el valor devuelto por su llamada 'read()'. * No hagas eso. * –

Respuesta

25

Usaría un archivo mapeado de memoria lo suficientemente rápido como para hacerlo en el mismo hilo.

final FileChannel channel = new FileInputStream(fileName).getChannel(); 
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); 

// when finished 
channel.close(); 

Esto supone que el archivo es más pequeño que 2 GB y tardará 10 milisegundos o menos.

+1

¡Diablos! ¿Por qué diablos es eso tan extremadamente rápido? Gracias de todos modos, funciona a la perfección. (editar: obtiene el archivo de la memoria, los documentos java me acaban de decir. inteligente) –

+1

Si necesita acceder a más de 2 GB, necesita utilizar más de una asignación. –

3

No utilice available(): no es confiable. Y no ignore el resultado del método read(): le dice cuántos bytes se leyeron realmente. Y si quieres leer todo en la memoria, utilice un ByteArrayOutputStream lugar de utilizar un List<byte[]>:

ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
int read; 
while ((read = reader.read(buffer)) >= 0) { 
    baos.write(buffer, 0, read); 
} 
byte[] everything = baos.toByteArray(); 

creo que 1024 es un poco pequeña como un tamaño de búfer. Utilizaría un búfer más grande (algo así como 16 KB o 32 KB)

Tenga en cuenta que Apache commons IO y Guava tienen métodos de utilidad que hacen esto por usted, y que ya se han optimizado.

1

Eche un vistazo a la API Java NIO (entrada/salida no bloqueada). Además, this question podría ser útil.

No tengo mucha experiencia con IO, pero he escuchado que NIO es una forma mucho más eficiente de manejar grandes conjuntos de datos.

Cuestiones relacionadas