簡體   English   中英

如何使用Java處理龐大的單行文件

[英]How to deal with a huge, one-line file in Java

我需要讀取一個巨大的文件(15 + GB)並執行一些小的修改(添加一些換行符,以便不同的解析器可以實際使用它)。 你可能認為通常有這樣做的答案:

但我的整個文件都在一行。

到目前為止我的一般方法是非常基本的:

char[] buffer = new char[X];
BufferedReader reader = new BufferedReader(new ReaderUTF8(new FileInputStream(new File("myFileName"))), X);
char[] bufferOut = new char[X+a little];
int bytesRead = -1;
int i = 0;
int offset = 0;
long totalBytesRead = 0;
int countToPrint = 0;
while((bytesRead = reader.read(buffer)) >= 0){
    for(i = 0; i < bytesRead; i++){
        if(buffer[i] == '}'){
            bufferOut[i+offset] = '}';
            offset++;
            bufferOut[i+offset] = '\n';
        }
        else{
            bufferOut[i+offset] = buffer[i];
        }
    }
    writer.write(bufferOut, 0, bytesRead+offset);
    offset = 0;
    totalBytesRead += bytesRead;
    countToPrint += 1;
    if(countToPrint == 10){
        countToPrint = 0;
        System.out.println("Read "+((double)totalBytesRead / originalFileSize * 100)+" percent.");
    }
}
writer.flush();

經過一些實驗,我發現X大於一百萬的值給出了最佳速度 - 看起來我每10分鍾得到2%左右,而X值約為60,000只在15小時內得到60% 。 分析顯示我在read()方法中花費了96%以上的時間,所以這絕對是我的瓶頸。 在編寫本文時,我的800萬X版本在2小時40分鍾后完成了32%的文件,以防您想知道它是如何長期執行的。

有沒有更好的方法來處理這么大的單行文件? 有,是否有更快的方式來讀取這種類型的文件,這使我有一個相對簡單的方法來插入換行符?

我知道不同的語言或程序可能會優雅地處理這個問題,但我將其限制在Java的角度。

你正在使它變得比它應該復雜得多。 通過使用標准類已經提供的緩沖,您應該獲得每秒至少幾MB的麻煩,沒有任何麻煩。

這個簡單的測試程序在我的電腦上在不到2分鍾的時間內處理1GB(包括創建測試文件):

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Random;

public class TestFileProcessing {

    public static void main(String[] argv) {

        try {
            long time = System.currentTimeMillis();
            File from = new File("C:\\Test\\Input.txt");
            createTestFile(from, StandardCharsets.UTF_8, 1_000_000_000);
            System.out.println("Created file in: " + (System.currentTimeMillis() - time) + "ms");

            time = System.currentTimeMillis();
            File to = new File("C:\\Test\\Output.txt");
            doIt(from, to, StandardCharsets.UTF_8);
            System.out.println("Converted file in: " + (System.currentTimeMillis() - time) + "ms");
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    public static void createTestFile(File file, Charset encoding, long size) throws IOException {
        Random r = new Random(12345);
        try (OutputStream fout = new FileOutputStream(file);
                BufferedOutputStream bout = new BufferedOutputStream(fout);
                Writer writer = new OutputStreamWriter(bout, encoding)) {
            for (long i=0; i<size; ++i) {
                int c = r.nextInt(26);
                if (c == 0)
                    writer.write('}');
                else
                    writer.write('a' + c);
            }
        }
    }

    public static void doIt(File from, File to, Charset encoding) throws IOException {
        try (InputStream fin = new FileInputStream(from);
                BufferedInputStream bin = new BufferedInputStream(fin);
                Reader reader = new InputStreamReader(bin, encoding);
                OutputStream fout = new FileOutputStream(to);
                BufferedOutputStream bout = new BufferedOutputStream(fout);
                Writer writer = new OutputStreamWriter(bout, encoding)) {
            int c;
            while ((c = reader.read()) >= 0) {
                if (c == '}')
                    writer.write('\n');
                writer.write(c);
            }
        }
    }

}

如您所見,沒有使用復雜的邏輯或過多的緩沖區大小。 使用的是簡單地緩沖最靠近硬件的流,即FileInput / OutputStream。

暫無
暫無

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

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