2011-05-02 40 views
9

Estoy trabajando en un programa que tiene aproximadamente 400 archivos de entrada y aproximadamente 40 archivos de salida. Es simple: Lee cada archivo de entrada y genera un archivo nuevo pero mucho más grande (basado en un algoritmo).Forma más rápida de leer el archivo

estoy usando el método read() de BufferedReader:

String encoding ="ISO-8859-1"; 
FileInputStream fis = new FileInputStream(nextFile); 
BufferedReader reader = new BufferedReader(new InputStreamReader(fis, encoding)); 
char[] buffer = new char[8192] ; 

Para leer los archivos de entrada que estoy usando esto:

private String getNextBlock() throws IOException{ 
    boolean isNewFile = false; 

    int n = reader.read(buffer, 0, buffer.length); 
    if(n == -1) { 
     return null; 
    } else { 
     return new String(buffer,0,n); 
    } 
} 

Con cada bloque que estoy haciendo algunas comprobaciones (como buscar una cadena dentro del bloque) y luego lo estoy escribiendo en un archivo:

BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
     new FileOutputStream("fileName"), encoding)); 

writer.write(textToWrite); 

El problema es que ta kes unos 12 minutos. Estoy tratando de encontrar algo mucho más rápido. ¿Alguien tiene alguna idea sobre algo mejor?

Gracias.

+0

¿Has probado la evaluación comparativa de diferentes tamaños de buffer? – netbrain

+0

Sí, y es lo mismo. –

+1

¿El cuello de botella está en el archivo IO o en el algoritmo que está utilizando para combinar los datos? – scaganoff

Respuesta

21

Usted debe ser capaz de encontrar una respuesta aquí:

http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly

Para obtener el mejor rendimiento de Java leer, hay cuatro cosas que recordar:

  • Minimizar operaciones I/O de leyendo una matriz a la vez, no un byte a la vez. Una matriz de 8Kbytes tiene un buen tamaño.

  • Minimice las llamadas al método obteniendo datos de una matriz a la vez, no de un byte a la vez. Use indexación de matriz para obtener bytes en la matriz.

  • Minimice los bloqueos de sincronización de subprocesos si no necesita seguridad de subprocesos. Realice menos llamadas a métodos a una clase segura para subprocesos o use una clase no segura para subprocesos como FileChannel y MappedByteBuffer.

  • Minimice la copia de datos entre la JVM/OS, las memorias intermedias internas y las matrices de aplicaciones. Use FileChannel con mapeo de memoria, o una matriz directa o envolvente ByteBuffer.

+4

Las respuestas de solo enlace no son ideales. ¿Podría al menos resumir los hallazgos del artículo? (¡Gracias!) –

+1

Solucionado ahora. Su bienvenida – netbrain

4

Como usted no da demasiados detalles, podría sugest que trate de usar memoria utilizan archivos asignados:

FileInputStream f = new FileInputStream(fileName); 
FileChannel ch = f.getChannel(); 
MappedByteBuffer mbb = ch.map(ch.MapMode.READ_ONLY, 0L, ch.size()); 
while (mbb.hasRemaining()) { 
     // Access the data using the mbb 
} 

Es posible opitmize si usted daría más acerca detailt qué tipo de datos tienen tus archivos

EDITAR

¿Dónde está la // acceder a la fecha usando el MBB, tienes frío decodificar el texto:

String charsetName = "UTF-16"; // choose the apropriate charset. 
CharBuffer cb = Charsert.forName(charsetName).decode(mbb); 
String text = cb.toString(); 
+0

El OP quiere leer el archivo como texto. Puede incluir cómo leer MappedByteBuffer con la codificación predeterminada (o una específica como UTF-8) –

+0

Mientras lee el archivo asignado como bytes, no importa el endoding. Tendrá que especificar la codificación al construir el String: String s = new String (mbb.array(), Charset.UTF-8), teniendo cuidado si el array está cargado, si no es así, será necesario leer usando asCharBuffer() y también deben saber el tamaño y el contenido de la matriz. – Pih

+0

Ah, pero el diablo está en los detalles. ;) Por ejemplo, no se puede decodificar una Cadena donde se ha leído un byte de un carácter, pero otro no. ;) No creo que puedas llamar 'mbb.array()' en un MappedByteBuffer –

1

memorias intermedias asignadas byte es la manera más rápida:

FileInputStream f = new FileInputStream(name); 
FileChannel ch = f.getChannel(); 
MappedByteBuffer mb = ch.map(ch.MapMode.READ_ONLY, 
    0L, ch.size()); 
byte[] barray = new byte[SIZE]; 
long checkSum = 0L; 
int nGet; 
while(mb.hasRemaining()) 
{ 
    nGet = Math.min(mb.remaining(), SIZE); 
    mb.get(barray, 0, nGet); 
    for (int i=0; i<nGet; i++) 
    checkSum += barray[i]; 
} 
+1

no funciona para archivos grandes, que tienen un tamaño mayor que Integer.MAX_VALUE – halil

Cuestiones relacionadas