簡體   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