web-dev-qa-db-fra.com

Le moyen le plus rapide d'écrire dans un fichier?

J'ai créé une méthode qui prend une File et une String. Il remplace le fichier par un nouveau fichier contenant cette chaîne.

Voici ce que j'ai fait: 

public static void Save(File file, String textToSave) {

    file.delete();
    try {
        BufferedWriter out = new BufferedWriter(new FileWriter(file));
        out.write(textToSave);
        out.close();
    } catch (IOException e) {
    }
}

Cependant, il est douloureusement lent. Cela prend parfois plus d'une minute.

Comment puis-je écrire des fichiers volumineux contenant des dizaines de milliers voire un million de caractères?

31
user263078

Assurez-vous d’allouer un tampon suffisamment grand:

BufferedWriter out = new BufferedWriter(new FileWriter(file), 32768);

Quel type de système d'exploitation utilisez-vous? Cela peut aussi faire une grande différence. Cependant, prendre minute pour écrire un fichier de taille inférieure à énorme ressemble à un problème système. Sur Linux ou d’autres systèmes * ix, vous pouvez utiliser des éléments tels que strace pour voir si la JVM effectue de nombreux appels système inutiles. (Il y a très longtemps, Java I/O était plutôt stupide et émettait un nombre insensé d'appels système write() de bas niveau si vous ne faisiez pas attention, mais quand je dis "il y a longtemps", je veux dire 1998 ou plus.)

edit - notez que la situation d'un programme Java écrivant un fichier simple de manière simple, et pourtant très lente, est par nature étrange. Pouvez-vous dire si le processeur est lourdement chargé pendant l'écriture du fichier? Cela ne devrait pas être; il devrait y avoir presque pas de charge de processeur d'une telle chose. 

19
Pointy

Un test simple pour vous

char[] chars = new char[100*1024*1024];
Arrays.fill(chars, 'A');
String text = new String(chars);
long start = System.nanoTime();
BufferedWriter bw = new BufferedWriter(new FileWriter("/tmp/a.txt"));
bw.write(text);
bw.close();
long time = System.nanoTime() - start;
System.out.println("Wrote " + chars.length*1000L/time+" MB/s.");

Impressions

Wrote 135 MB/s.
14
Peter Lawrey

Vous pouvez examiner les capacités de Java NIO. Cela peut soutenir ce que vous voulez faire.

Java NIO FileChannel vs FileOutputstream performance/utilité

5
Wouter Lievens

Essayez d’utiliser des fichiers mappés en mémoire:

FileChannel rwChannel = new RandomAccessFile("textfile.txt", "rw").getChannel();
ByteBuffer wrBuf = rwChannel.map(FileChannel.MapMode.READ_WRITE, 0, textToSave.length());

wrBuf.put(textToSave.getBytes());

rwChannel.close();
3
Deepak Agarwal

Bonjour, j'ai créé deux approches pour créer de gros fichiers, exécuter le programme sur Windows 7, 64 bits, 8 Go RAM machine, JDK 8 et moins sont des résultats.
Dans les deux cas, fichier de 180 Mo créé contenant un nombre dans chaque ligne de 1 à 20 millions (2 crore dans le système indien).

La mémoire du programme Java augmente progressivement jusqu'à 600 Mo

Première sortie

Approach = approach-1 (Using FileWriter)
Completed file writing in milli seconds = 4521 milli seconds.

Deuxième sortie

Approach = approach-2 (Using FileChannel and ByteBuffer)
Completed file writing in milli seconds = 3590 milli seconds.

Une observation - Je calcule la position (variable pos) dans l'approche n ° 2; si je la commente, seule la dernière chaîne sera visible car elle est écrasée à la position, mais le temps est réduit à près de 2000 millisecondes.

Code attaché.

import Java.io.FileWriter;
import Java.io.IOException;
import Java.io.RandomAccessFile;
import Java.nio.ByteBuffer;
import Java.nio.channels.FileChannel;
import Java.util.concurrent.TimeUnit;

public class TestLargeFile {

    public static void main(String[] args) {
        writeBigFile();
    }

    private static void writeBigFile() {
        System.out.println("--------writeBigFile-----------");
        long nanoTime = System.nanoTime();
        String fn = "big-file.txt";
        boolean approach1 = false;
        System.out.println("Approach = " + (approach1 ? "approach-1" : "approach-2"));
        int numLines = 20_000_000;
        try {
            if (approach1) {
                //Approach 1 -- for 2 crore lines takes 4.5 seconds with 180 mb file size
                approach1(fn, numLines);
            } else {
                //Approach 2 -- for 2 crore lines takes nearly 2 to 2.5 seconds with 180 mb file size
                approach2(fn, numLines);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("Completed file writing in milli seconds = " + TimeUnit.MILLISECONDS.convert((System.nanoTime() - nanoTime), TimeUnit.NANOSECONDS));
    }

    private static void approach2(String fn, int numLines) throws IOException {
        StringBuilder sb = new StringBuilder();
        FileChannel rwChannel = new RandomAccessFile(fn, "rw").getChannel();
        ByteBuffer wrBuf;

        int pos = 0;
        for (int i = 1; i <= numLines; i++) {
            sb.append(i).append(System.lineSeparator());
            if (i % 100000 == 0) {
                wrBuf = rwChannel.map(FileChannel.MapMode.READ_WRITE, pos, sb.length());
                pos += sb.length();
                wrBuf.put(sb.toString().getBytes());
                sb = new StringBuilder();
            }
        }
        if (sb.length() > 0) {
            wrBuf = rwChannel.map(FileChannel.MapMode.READ_WRITE, pos, sb.length());
            wrBuf.put(sb.toString().getBytes());
        }
        rwChannel.close();
    }

    private static void approach1(String fn, int numLines) throws IOException {
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i <= numLines; i++) {
            sb.append(i).append(System.lineSeparator());
        }
        FileWriter fileWriter = new FileWriter(fn);
        fileWriter.write(sb.toString());
        fileWriter.flush();
        fileWriter.close();
    }
}
0
shaILU