Java多重打开和写入文件的关闭

时间:2017-09-24 21:06:03

标签: java io

以下是我将ConcurrentMap<String, List<String>>写入文件的类。映射中的键是路径,映射中的值将按顺序写入文件。每次地图中有1,000个值时,都会调用此Task<Void>

public class MapWriter extends Task<Void> {

private final ParsingProducerConsumerContext context;

public MapWriter(ParsingProducerConsumerContext context) {
    this.context = context;
}

@Override
protected Void call() throws Exception {
    if (!isCancelled() || !context.isEmpty()) {
        ConcurrentMap<String, List<String>> jsonObjectMap = context.fetchAndReset();

        jsonObjectMap.entrySet().forEach((t) -> {                
            try {
                FileUtils.writeLines(new File(context.getPath() + t.getKey() + "\\sorted.json"), t.getValue(), true);
            } catch (IOException ex) {
                context.getLogger().log("Error writing to disk:");
                context.getLogger().log(ex.toString());
                context.stopEverything();
            }
        });

        context.getLogger().log(jsonObjectMap.values().stream().mapToInt(List::size).sum() + " schedules written to disk ");
    } else {
        context.getLogger().log("Nothing to write");
    }

    return null;
}
}

此任务一直在运行,生产者Task逐行读取〜2GByte文件,由消费者处理并放入ConcurrentMap<String, List<String>>

虽然这确实有用,但速度很慢!

我的研究表明,重复打开和关闭文件会产生足够的开销,从而影响性能,所以想知道以下方法是否会更好?

维护Map<String, File>File个已打开的对象。 如果ConcurrentMap<String, List<String>>中的密钥对应于打开的文件,请使用该File引用进行写入 完成所有处理后,循环Map<String, File>值并关闭每个文件。

这听起来是否合理?虽然会打开大约100个文件。

编辑::我使用System.nanoTime()做了一个简单的基准测试。生产者逐行导入的文件大约为2GB,每行在6kb到10kb之间(在List<String>中)。

此外,遇到OutOfMemory错误!我猜是因为2GByte被有效地加载到内存中,并没有足够快地写出来?

514 jsonObjects written to disk in 2258007ms 538 jsonObjects written to disk in 2525166ms 1372 jsonObjects written to disk in 169959ms 1690 jsonObjects written to disk in 720824ms 9079 jsonObjects written to disk in 5221168ms 22552 jsonObjects written to disk in 6943207ms 13392 jsonObjects written to disk in 6475639ms 0 jsonObjects written to disk in 6ms 0 jsonObjects written to disk in 5ms 0 jsonObjects written to disk in 5ms 40 jsonObjects written to disk in 23108ms 631 jsonObjects written to disk in 200269ms 3883 jsonObjects written to disk in 2054177ms Producer failed with java.lang.OutOfMemoryError: GC overhead limit exceeded

为了完整性,这里是Producer类:

public class NRODJsonProducer extends Task<Void> {

private final ParsingProducerConsumerContext context;

public NRODJsonProducer(ParsingProducerConsumerContext context) {
    this.context = context;
}

@Override
protected Void call() throws Exception {
    context.getLogger().log("Producer created");

    LineIterator li = FileUtils.lineIterator(new File(context.getPath() + context.getFilterFile()));

    while (li.hasNext()) {
        try {
            context.getQueue().put(li.next());
        } catch (InterruptedException ex) {
            Logger.getLogger(NRODJsonProducer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    LineIterator.closeQuietly(li);

    context.getLogger().log("Producer finished...");

    return null;
}

}

1 个答案:

答案 0 :(得分:0)

我不明白为什么。此代码将具有相同名称的文件的密钥写入所有内容,然后转到下一个密钥。如果生产者为该密钥生成另一个条目,它将覆盖前一个条目,此代码将再次写入该文件。保持文件打开不会有帮助。

真正的问题似乎是你一直在向文件写入相同的数据,因为你永远不会从地图中删除已处理的密钥。

NB你的工具条件错了。它应该是

if (!isCancelled() && !context.isEmpty())