Самый быстрый способ записи в файл? - PullRequest
31 голосов
/ 02 января 2011

Я сделал метод, который принимает File и String. Он заменяет файл новым файлом с этой строкой в ​​качестве его содержимого.

Вот что я сделал:

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) {
    }
}

Однако это мучительно медленно. Иногда это занимает больше минуты.

Как я могу написать большие файлы длиной от десятков тысяч до, возможно, до миллиона символов?

Ответы [ 6 ]

20 голосов
/ 02 января 2011

Убедитесь, что вы выделяете достаточно большой буфер:

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

На каких ОС вы работаете?Это тоже может иметь большое значение.Тем не менее, минута , чтобы записать файл менее огромного размера, звучит как системная проблема.В Linux или других системах * ix вы можете использовать такие вещи, как strace, чтобы узнать, выполняет ли JVM множество ненужных системных вызовов.(Давным-давно Java I / O был довольно тупым и делал безумные числа низкоуровневых системных вызовов write(), если вы не были осторожны, но когда я говорю «давным-давно», я имею в виду 1998 год или около.)

edit - обратите внимание, что ситуация, когда Java-программа пишет простой файл простым способом, хотя и очень медленная, по своей природе является странной.Можете ли вы сказать, сильно ли загружен процессор во время записи файла?Не должно быть;от такой вещи почти не должно быть нагрузки на процессор.

16 голосов
/ 02 января 2011

Простой тест для вас

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.");

Печать

Wrote 135 MB/s.
5 голосов
/ 02 января 2011

Вы можете посмотреть на возможности Java NIO. Это может поддержать то, что вы хотите сделать.

Java NIO FileChannel против FileOutputstream производительность / полезность

3 голосов
/ 17 февраля 2011

Попробуйте использовать файлы с отображением в памяти:

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();
0 голосов
/ 23 января 2018

Привет! Я создал два подхода к созданию больших файлов, запустил программу на Windows 7, 64-битная машина с 8 ГБ ОЗУ, JDK 8 и ниже.
В обоих случаях создается файл размером 180 МБ, содержащий число в каждой строке от 1 до 20 миллионов (2 крор в индийской системе).

Объем памяти программ на Java постепенно увеличивается до 600 МБ

Первый вывод

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

Второй выход

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

Одно наблюдение - я вычисляю позицию (переменную pos) в подходе # 2, если я закомментирую это, тогда будет видна только последняя строка из-за перезаписи в позиции, но время уменьшится почти до 2000 миллисекунд.

Код прикрепления.

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 голосов
/ 02 января 2011

В Java BufferWriter очень медленный: используйте нативные методы напрямую и вызывайте их как можно меньше (предоставьте им как можно больше данных за вызов).

    try{
        FileOutputStream file=new FileOutputStream(file);
        file.write(content);
        file.close();
    }catch(Throwable e){
        D.error(e);
    }//try

Кроме того, удаление файла может занять некоторое время (возможно, оно сначала копируется в корзину). Просто перезапишите файл, как в приведенном выше коде.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...