Saltar al contenido

La forma más rápida de leer y escribir archivos grandes línea por línea en Java

Si encuentras algún detalle que te causa duda puedes comentarlo y te responderemos lo más rápido posible.

Solución:

Sospecho que su problema real es que tiene hardware limitado y lo que hace es software no hará mucha diferencia. Si tiene mucha memoria y CPU, los trucos más avanzados pueden ayudar, pero si solo está esperando en su disco duro porque el archivo no está en caché, no hará mucha diferencia.

Por cierto: 500 MB en 10 segundos o 50 MB / seg es una velocidad de lectura típica para un disco duro.

Intente ejecutar lo siguiente para ver en qué punto su sistema no puede almacenar en caché el archivo de manera eficiente.

public static void main(String... args) throws IOException 
    for (int mb : new int[]50, 100, 250, 500, 1000, 2000)
        testFileSize(mb);


private static void testFileSize(int mb) throws IOException 
    File file = File.createTempFile("test", ".txt");
    file.deleteOnExit();
    char[] chars = new char[1024];
    Arrays.fill(chars, 'A');
    String longLine = new String(chars);
    long start1 = System.nanoTime();
    PrintWriter pw = new PrintWriter(new FileWriter(file));
    for (int i = 0; i < mb * 1024; i++)
        pw.println(longLine);
    pw.close();
    long time1 = System.nanoTime() - start1;
    System.out.printf("Took %.3f seconds to write to a %d MB, file rate: %.1f MB/s%n",
            time1 / 1e9, file.length() >> 20, file.length() * 1000.0 / time1);

    long start2 = System.nanoTime();
    BufferedReader br = new BufferedReader(new FileReader(file));
    for (String line; (line = br.readLine()) != null; ) 
    
    br.close();
    long time2 = System.nanoTime() - start2;
    System.out.printf("Took %.3f seconds to read to a %d MB file, rate: %.1f MB/s%n",
            time2 / 1e9, file.length() >> 20, file.length() * 1000.0 / time2);
    file.delete();

En una máquina Linux con mucha memoria.

Took 0.395 seconds to write to a 50 MB, file rate: 133.0 MB/s
Took 0.375 seconds to read to a 50 MB file, rate: 140.0 MB/s
Took 0.669 seconds to write to a 100 MB, file rate: 156.9 MB/s
Took 0.569 seconds to read to a 100 MB file, rate: 184.6 MB/s
Took 1.585 seconds to write to a 250 MB, file rate: 165.5 MB/s
Took 1.274 seconds to read to a 250 MB file, rate: 206.0 MB/s
Took 2.513 seconds to write to a 500 MB, file rate: 208.8 MB/s
Took 2.332 seconds to read to a 500 MB file, rate: 225.1 MB/s
Took 5.094 seconds to write to a 1000 MB, file rate: 206.0 MB/s
Took 5.041 seconds to read to a 1000 MB file, rate: 208.2 MB/s
Took 11.509 seconds to write to a 2001 MB, file rate: 182.4 MB/s
Took 9.681 seconds to read to a 2001 MB file, rate: 216.8 MB/s

En una máquina con Windows con mucha memoria.

Took 0.376 seconds to write to a 50 MB, file rate: 139.7 MB/s
Took 0.401 seconds to read to a 50 MB file, rate: 131.1 MB/s
Took 0.517 seconds to write to a 100 MB, file rate: 203.1 MB/s
Took 0.520 seconds to read to a 100 MB file, rate: 201.9 MB/s
Took 1.344 seconds to write to a 250 MB, file rate: 195.4 MB/s
Took 1.387 seconds to read to a 250 MB file, rate: 189.4 MB/s
Took 2.368 seconds to write to a 500 MB, file rate: 221.8 MB/s
Took 2.454 seconds to read to a 500 MB file, rate: 214.1 MB/s
Took 4.985 seconds to write to a 1001 MB, file rate: 210.7 MB/s
Took 5.132 seconds to read to a 1001 MB file, rate: 204.7 MB/s
Took 10.276 seconds to write to a 2003 MB, file rate: 204.5 MB/s
Took 9.964 seconds to read to a 2003 MB file, rate: 210.9 MB/s

Lo primero que intentaría es aumentar el tamaño del búfer de BufferedReader y BufferedWriter. Los tamaños de búfer predeterminados no están documentados, pero al menos en Oracle VM son 8192 caracteres, lo que no traerá mucha ventaja de rendimiento.

Si solo necesita hacer una copia del archivo (y no necesita acceso real a los datos), dejaría de usar el enfoque Reader / Writer y trabajaría directamente con InputStream y OutputStream usando un byte array como búfer:

FileInputStream fis = new FileInputStream("d:/test.txt");
FileOutputStream fos = new FileOutputStream("d:/test2.txt");
byte[] b = new byte[bufferSize];
int r;
while ((r=fis.read(b))>=0) 
    fos.write(b, 0, r);         

fis.close();
fos.close();

o realmente usa NIO:

FileChannel in = new RandomAccessFile("d:/test.txt", "r").getChannel();
FileChannel out = new RandomAccessFile("d:/test2.txt", "rw").getChannel();
out.transferFrom(in, 0, Long.MAX_VALUE);
in.close();
out.close();

Sin embargo, al comparar los diferentes métodos de copia, tengo diferencias (duración) mucho más grandes entre cada ejecución del punto de referencia que entre las diferentes implementaciones. El almacenamiento en caché de E / S (tanto a nivel del sistema operativo como del caché del disco duro) juega un gran papel aquí y es muy difícil decir qué es más rápido. En mi hardware, copiar un archivo de texto de 1GB línea por línea usando BufferedReader y BufferedWriter toma menos de 5 segundos en algunas ejecuciones y más de 30 segundos en otras.

En Java 7 puede utilizar los métodos Files.readAllLines () y Files.write (). Aquí está el ejemplo:

List readTextFile(String fileName) throws IOException 
    Path path = Paths.get(fileName);
    return Files.readAllLines(path, StandardCharsets.UTF_8);


void writeTextFile(List strLines, String fileName) throws IOException 
    Path path = Paths.get(fileName);
    Files.write(path, strLines, StandardCharsets.UTF_8);

Valoraciones y comentarios

Puedes asistir nuestra investigación añadiendo un comentario o dejando una valoración te estamos eternamente agradecidos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *