如何使用最小RAM

时间:2017-11-22 14:56:33

标签: java memory-management io

我的目标是从大文件中读取,一次处理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){

            }
        }
    });

最后,我尝试使用InputStreamscanner来阅读文件,并使用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比我喜欢的要多。

提前致谢,

山姆

2 个答案:

答案 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个刷新。