繁体   English   中英

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

[英]Java Multiple Opening and Closing of Files for Writing

下面是我有一个将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>>

虽然这确实有效,但速度非常慢!

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

维护打开的File对象的Map<String, 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;
}

}

我不明白为什么。 此代码将密钥的所有内容写到同名文件中,然后继续进行下一个密钥。 如果生产者为该密钥产生另一个条目,它将覆盖先前的条目,并且此代码将再次写入文件。 保持文件打开无济于事。

真正的问题似乎是您一直将相同的数据写入文件,因为您从未从映射中删除已处理的密钥。

注意:您的使用情况是错误的。 它应该是

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM