74 votes

Le moyen le plus rapide d'écrire d'énormes données dans un fichier texte Java

Je dois écrire d'énormes données dans un fichier texte [csv]. J'ai utilisé BufferedWriter pour écrire les données et cela a pris environ 40 secondes pour écrire 174 Mo de données. Est-ce la vitesse la plus rapide que java peut offrir?

 bufferedWriter = new BufferedWriter ( new FileWriter ( "fileName.csv" ) );
 

Remarque: Ces 40 secondes incluent le temps d'itération et de récupération des enregistrements à partir du jeu de résultats. :) 174 Mo correspond à 400 000 lignes dans le jeu de résultats.

110voto

David Moles Points 7669

Vous pouvez essayer de supprimer BufferedWriter et d’utiliser directement FileWriter. Sur un système moderne, il est fort probable que vous écriviez simplement dans la mémoire cache du lecteur.

Il me faut entre 4 et 5 secondes pour écrire 175 Mo (4 millions de chaînes) - sur un Dell double cœur 2,4 GHz fonctionnant sous Windows XP avec un disque Hitachi de 80 Go à 7 200 tr / min.

Pouvez-vous isoler combien de temps correspond à la récupération des enregistrements et combien d'écriture de fichier?

 import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;

public class FileWritingPerfTest {


private static final int ITERATIONS = 5;
private static final double MEG = (Math.pow(1024, 2));
private static final int RECORD_COUNT = 4000000;
private static final String RECORD = "Help I am trapped in a fortune cookie factory\n";
private static final int RECSIZE = RECORD.getBytes().length;

public static void main(String[] args) throws Exception {
    List<String> records = new ArrayList<String>(RECORD_COUNT);
    int size = 0;
    for (int i = 0; i < RECORD_COUNT; i++) {
        records.add(RECORD);
        size += RECSIZE;
    }
    System.out.println(records.size() + " 'records'");
    System.out.println(size / MEG + " MB");

    for (int i = 0; i < ITERATIONS; i++) {
        System.out.println("\nIteration " + i);

        writeRaw(records);
        writeBuffered(records, 8192);
        writeBuffered(records, (int) MEG);
        writeBuffered(records, 4 * (int) MEG);
    }
}

private static void writeRaw(List<String> records) throws IOException {
    File file = File.createTempFile("foo", ".txt");
    try {
        FileWriter writer = new FileWriter(file);
        System.out.print("Writing raw... ");
        write(records, writer);
    } finally {
        // comment this out if you want to inspect the files afterward
        file.delete();
    }
}

private static void writeBuffered(List<String> records, int bufSize) throws IOException {
    File file = File.createTempFile("foo", ".txt");
    try {
        FileWriter writer = new FileWriter(file);
        BufferedWriter bufferedWriter = new BufferedWriter(writer, bufSize);

        System.out.print("Writing buffered (buffer size: " + bufSize + ")... ");
        write(records, bufferedWriter);
    } finally {
        // comment this out if you want to inspect the files afterward
        file.delete();
    }
}

private static void write(List<String> records, Writer writer) throws IOException {
    long start = System.currentTimeMillis();
    for (String record: records) {
        writer.write(record);
    }
    writer.flush();
    writer.close();
    long end = System.currentTimeMillis();
    System.out.println((end - start) / 1000f + " seconds");
}
}
 

43voto

Deepak Agarwal Points 112

essayez les fichiers mappés en mémoire (il faut 300 m / s pour écrire 174 Mo dans mon m / c, noyau 2 duo, 2,5 Go de RAM):

 byte[] buffer = "Help I am trapped in a fortune cookie factory\n".getBytes();
int number_of_lines = 400000;

FileChannel rwChannel = new RandomAccessFile("textfile.txt", "rw").getChannel();
ByteBuffer wrBuf = rwChannel.map(FileChannel.MapMode.READ_WRITE, 0, buffer.length * number_of_lines);
for (int i = 0; i < number_of_lines; i++)
{
    wrBuf.put(buffer);
}
rwChannel.close();
 

20voto

Seulement pour des raisons de statistiques:

La machine est vieux Dell avec le nouveau SSD

CPU: Intel Pentium D 2,8 Ghz

SSD: SSD Patriot Inferno 120 Go

 4000000 'records'
175.47607421875 MB

Iteration 0
Writing raw... 3.547 seconds
Writing buffered (buffer size: 8192)... 2.625 seconds
Writing buffered (buffer size: 1048576)... 2.203 seconds
Writing buffered (buffer size: 4194304)... 2.312 seconds

Iteration 1
Writing raw... 2.922 seconds
Writing buffered (buffer size: 8192)... 2.406 seconds
Writing buffered (buffer size: 1048576)... 2.015 seconds
Writing buffered (buffer size: 4194304)... 2.282 seconds

Iteration 2
Writing raw... 2.828 seconds
Writing buffered (buffer size: 8192)... 2.109 seconds
Writing buffered (buffer size: 1048576)... 2.078 seconds
Writing buffered (buffer size: 4194304)... 2.015 seconds

Iteration 3
Writing raw... 3.187 seconds
Writing buffered (buffer size: 8192)... 2.109 seconds
Writing buffered (buffer size: 1048576)... 2.094 seconds
Writing buffered (buffer size: 4194304)... 2.031 seconds

Iteration 4
Writing raw... 3.093 seconds
Writing buffered (buffer size: 8192)... 2.141 seconds
Writing buffered (buffer size: 1048576)... 2.063 seconds
Writing buffered (buffer size: 4194304)... 2.016 seconds
 

Comme on peut le voir, la méthode brute est plus lente que la mémoire tampon.

5voto

Brian Agnew Points 143181

Votre vitesse de transfert est susceptible de ne pas être limité par Java. Au lieu de cela je soupçonne (dans aucun ordre particulier)

  1. la vitesse de transfert à partir de la base de données
  2. la vitesse de transfert sur le disque

Si vous lisez les données complètes, et puis l'écrire sur le disque, alors qui va prendre plus de temps, depuis la JVM va allouer de la mémoire et de la db rea/écriture sur le disque va se passer de manière séquentielle. Au lieu de cela, je voudrais écrire dans la mémoire tampon de l'écrivain pour chaque lecture que vous faites de la db, et donc, l'opération sera plus proche d'un concurrent à un (je ne sais pas si vous faites cela ou pas)

4voto

gpeche Points 8596

Pour ces lectures volumineuses de la base de données, vous pouvez ajuster la taille d'extraction de votre instruction. Cela pourrait économiser beaucoup d'allers et retours pour DB.

http://download.oracle.com/javase/1.5.0/docs/api/java/sql/Statement.html#setFetchSize%28int%29

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X