我的目标是从大文件中读取,一次处理2行,并将结果写入新文件。这些文件可能会变得非常大,从1GB到150GB不等,所以我想尝试使用尽可能少的RAM进行此处理
处理非常简单:由制表符分隔的行拆分,选择某些元素,并将新的String写入新文件。
到目前为止,我尝试使用BufferedReader
来读取文件,并PrintWriter
将行输出到文件中:
while((line1 = br.readLine()) != null){
if(!line1.startsWith("@")){
line2 = br.readLine();
recordCount++;
one.println(String.format("%s\n%s\n+\n%s",line1.split("\t")[0] + ".1", line1.split("\t")[9], line1.split("\t")[10]));
two.println(String.format("%s\n%s\n+\n%s",line2.split("\t")[0] + ".2", line2.split("\t")[9], line2.split("\t")[10]));
}
}
我还尝试使用Java8 Streams从文件中读取和写入:
stream.forEach(line -> {
if(!line.startsWith("@")) {
try {
if (counter.getAndIncrement() % 2 == 0)
Files.write(path1, String.format("%s\n%s\n+\n%s", line.split("\t")[0] + ".1", line.split("\t")[9], line.split("\t")[10]).getBytes(), StandardOpenOption.APPEND);
else
Files.write(path2, String.format("%s\n%s\n+\n%s", line.split("\t")[0] + ".2", line.split("\t")[9], line.split("\t")[10]).getBytes(), StandardOpenOption.APPEND);
}catch(IOException ioe){
}
}
});
最后,我尝试使用InputStream
和scanner
来阅读文件,并使用PrintWriter
来输出这些行:
inputStream = new FileInputStream(inputFile);
sc = new Scanner(inputStream, "UTF-8");
String line1, line2;
PrintWriter one = new PrintWriter(new FileOutputStream(dotOne));
PrintWriter two = new PrintWriter(new FileOutputStream(dotTwo));
while(sc.hasNextLine()){
line1 = sc.nextLine();
if(!line1.startsWith("@")) {
line2 = sc.nextLine();
one.println(String.format("%s\n%s\n+\n%s",line1.split("\t")[0] + ".1", line1.split("\t")[9], line1.split("\t")[10]));
two.println(String.format("%s\n%s\n+\n%s",line2.split("\t")[0] + ".2", line2.split("\t")[9], line2.split("\t")[10]));
}
}
我面临的问题是该程序似乎存储要写入的数据或输入文件数据到RAM中。
以上所有方法都可行,但使用的RAM比我喜欢的要多。
提前致谢,
山姆
答案 0 :(得分:0)
你没有尝试的是MemoryMappedByteBuffer。 FileChannel.map可能可用于您的目的,而不是在Java内存中分配。
使用自制字节缓冲区的函数代码为:
try (FileInputStream fis = new FileInputStream(source);
FileChannel fic = fis.getChannel();
FileOutputStream fos = new FileOutputStream(target);
FileChannel foc = fos.getChannel()) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (true) {
int nread = fic.read(buffer);
if (nread == -1) {}
break;
}
buffer.flip();
foc.write(buffer);
buffer.clear();
}
}
使用fic.map
连续将区域映射到OS内存似乎很容易,但是
我需要先测试一些更复杂的代码。
答案 1 :(得分:0)
创建PrintWriter时,将autoFlush设置为true:
new PrintWriter(new FileOutputStream(dotOne), true)
这样,缓冲的数据将用每println
个刷新。