2011-01-01 3 views
27

Я сделал способ, который принимает 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) { 
    } 
} 

Однако это мучительно медленно. Это иногда занимает минуту.

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

+8

Удаление файла не требуется. Вы переписываете его. –

+1

Сколько времени занимает процессор и время ввода/вывода («система»)? Для больших файлов создание огромной строки textToSave может доминировать во времени. – Raedwald

+3

Непосредственное отношение к вашему вопросу: Возможно, вы планируете реструктурировать инструкцию out.close(), чтобы ее можно было выполнить в блоке finally. В случае, если ошибка будет записана, она все равно будет закрыта. –

ответ

14

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

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

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

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

+0

Согласовано. Возможно, он даже сможет узнать размер буфера, необходимый заранее, так как он берет строку как param: textToSave.getBytes(). Length –

+0

@ Rocky Madden да, это действительно хорошая точка. Однако демпинг строки через библиотеки Java IO должен быть довольно быстрым практически любым способом, которым вы это делаете. – Pointy

+0

getBytes() может быть очень дорогим только для настройки буфера. Я предлагаю вам сделать это 256K и не беспокоиться об этом. –

-3

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

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

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

+0

У меня не было опыта работы с BufferedWriter, который был «очень медленным» вообще, и я писал код Java на стороне сервера очень долго. Я не думаю, что это то, что я бы использовал, если бы у меня было очень серьезное приложение с мега-пропускной способностью, но это не так уж плохо; Как это могло произойти? – Pointy

+1

Аналогичным образом, я никогда не видел вызова File # delete() переместить файл в корзину. Удалить означает удаление. –

+0

Pointy: Да, вероятно, было «давно», что я проследил файл Java, записывая через отладчик MS, чтобы увидеть унаследованное количество системных вызовов, которые он делал на моей машине. –

13

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

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. 
3

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

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

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

памяти программы Java постепенно растет до сих 600 MB

Первый выход

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. 

одно наблюдение - я вычисления позиции (переменная позиция) в подходе # 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(); 
    } 
} 
Смежные вопросы