我需要读取一个巨大的文件(15 GB)并执行一些小的修改(添加一些换行符,以便不同的解析器可以真正地使用它).您可能会认为已经有正常的答案:
> Reading a very huge file in java
> How to read a large text file line by line using Java?
但我的整个文件在一行.
目前我的一般做法是非常基本的:
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,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% .分析显示我花了96%的时间在read()方法中,这绝对是我的瓶颈.在撰写本文时,我的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.