簡體   English   中英

寫入文件的最快方法?

[英]Fastest way to write to file?

我做了一個采用FileString的方法。 它用該字符串作為其內容的新文件替換該文件。

這是我做的:

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

然而,它的速度非常緩慢。 有時需要一分鍾以上。

如何編寫包含數萬到一百萬個字符的大文件?

確保分配足夠大的緩沖區:

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

你在運行什么樣的操作系統? 這也可以產生很大的不同。 然而,花一分鍾寫出一個不太大的文件聽起來像是一個系統問題。 在Linux或其他* ix系統上,您可以使用strace東西來查看JVM是否正在進行大量不必要的系統調用。 (很久以前,Java I / O非常愚蠢,如果你不小心的話,會發出瘋狂的低級write()系統調用數,但是當我說“很久以前”我的意思是1998年左右。)

編輯 - 請注意,Java程序以簡單的方式編寫一個簡單文件,但速度非常慢的情況本質上是奇怪的。 在寫入文件時,能否判斷CPU是否負載過重? 不應該; 從這樣的事情應該幾乎沒有CPU負載。

一個簡單的測試

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.

您可以了解Java的NIO功能。 它可能支持你想做的事情。

Java NIO FileChannel與FileOutputstream的性能/實用性

嘗試使用內存映射文件:

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();

嗨我創建了兩種方法來創建大文件,在Windows 7,64位,8 GB RAM機器上運行程序,JDK 8及以下是結果。
在這兩種情況下,創建的180 MB文件包含每行中1到2千萬的數字(印度系統中為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中計算位置(pos變量),如果我將其注釋掉,那么由於在位置被覆蓋,只有最后一個字符串可見,但時間減少到接近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();
    }
}

此解決方案使用 Java NIO 創建包含字符串“ABCD...89\n”的 20GB 文件 10 * 2 億次。 MacBook Pro(2021 年起 14 英寸,M1 Pro,SSD AP1024R)的寫入性能約為 5.1 GB/s。

代碼如下:

 public static void main(String[] args) throws IOException { long number_of_lines = 1024 * 1024 * 200; int repeats = 10; byte[] buffer = "ABCD...89\n".getBytes(); FileChannel rwChannel = FileChannel.open(Path.of("textfile.txt"), StandardOpenOption.CREATE, StandardOpenOption.WRITE); // prepare buffer ByteBuffer wrBuf = ByteBuffer.allocate(buffer.length * (int) number_of_lines); for (int i = 0; i < number_of_lines; i++) wrBuf.put(buffer); long t1 = System.currentTimeMillis(); for(int i = 0; i < repeats; i++) { rwChannel.write(wrBuf); wrBuf.flip(); } while (wrBuf.hasRemaining()) { rwChannel.write(wrBuf); } long t2 = System.currentTimeMillis(); System.out.println("Time: " + (t2-t1)); System.out.println("Speed: " + ((double) number_of_lines * buffer.length*10 / (1024*1024)) / ((t2-t1) / (double) 1000) + " Mb/s"); }

在Java中,BufferWriter非常慢:直接使用本機方法,並盡可能少地調用它們(盡可能為每個調用提供盡可能多的數據)。

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

此外,刪除文件可能需要一段時間(可能首先將其復制到回收站)。 只需覆蓋文件,就像上面的代碼一樣。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM