您好,登錄后才能下訂單哦!
小編給大家分享一下Java如何使用Jackson編寫大型JSON文件,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
有時您需要將大量數據導出為 JSON 到一個文件。也許是“將所有數據導出到 JSON”,或者 GDPR“可移植性權利”,您實際上需要這樣做。
與任何大型數據集一樣,您不能將其全部放入內存并將其寫入文件。這需要一段時間,它從數據庫中讀取大量條目,您需要小心不要使此類導出使整個系統過載或耗盡內存。
幸運的是,在 JacksonSequenceWriter
和可選的管道流的幫助下,這樣做相當簡單。這是它的樣子:
private ObjectMapper jsonMapper =new ObjectMapper();
private ExecutorService executorService = Executors.newFixedThreadPool(5);
@Async
public ListenableFuture<Boolean> export(UUID customerId) {
try (PipedInputStream in =new PipedInputStream();
PipedOutputStream pipedOut =new PipedOutputStream(in);
GZIPOutputStream out =new GZIPOutputStream(pipedOut)) {
Stopwatch stopwatch = Stopwatch.createStarted();
ObjectWriter writer = jsonMapper.writer().withDefaultPrettyPrinter();
try(SequenceWriter sequenceWriter = writer.writeValues(out)) {
sequenceWriter.init(true);
Future<?> storageFuture = executorService.submit(() ->
storageProvider.storeFile(getFilePath(customerId), in));
int batchCounter =0;
while (true) {
List<Record> batch = readDatabaseBatch(batchCounter++);
for (Record record : batch) {
sequenceWriter.write(entry);
}
if (batch.isEmpty()) {
// if there are no more batches, stop.
break;
}
}
// wait for storing to complete
storageFuture.get();
// send the customer a notification and a download link
notifyCustomer(customerId);
}
logger.info("Exporting took {} seconds", stopwatch.stop().elapsed(TimeUnit.SECONDS));
return AsyncResult.forValue(true);
}catch (Exception ex) {
logger.error("Failed to export data", ex);
return AsyncResult.forValue(false);
}
}
代碼做了幾件事:
使用 SequenceWriter
連續寫入記錄。它使用 OutputStream
進行初始化,所有內容都寫入其中。這可以是簡單的 FileOutputStream
,也可以是下面討論的管道流。請注意,這里的命名有點誤導——writeValues(out)
聽起來你是在指示作者現在寫點什么;相反,它將其配置為稍后使用特定的流。
用SequenceWriter
初始化true
,意思是“包裹在數組中”。您正在編寫許多相同的記錄,因此它們應該在最終的 JSON 中表示一個數組。
使用PipedOutputStream
和PipedInputStream
將SequenceWriter
鏈接到InputStream
然后傳遞給存儲服務的 an
。如果我們明確地處理文件,就沒有必要了——只需傳遞 aFileOutputStream
就可以了。但是,您可能希望以不同的方式存儲文件,例如在 Amazon S3 中,并且 putObject
調用需要一個 InputStream
,從中讀取數據并將其存儲在 S3
中。因此,實際上,您正在寫入直接寫入 InputStream
的 OutputStream
,當嘗試從中讀取時,會將所有內容寫入另一個 OutputStream
存儲文件是在單獨的線程中調用的,這樣寫入文件不會阻塞當前線程,其目的是從數據庫中讀取。同樣,如果使用簡單的 FileOutputStream
,則不需要這樣做。
整個方法被標記為@Async (spring)
以便它不會阻塞執行——它在準備好時被調用并完成(使用具有有限線程池的內部 Spring 執行程序服務)
數據庫批量讀取代碼這里沒有顯示,因為它因數據庫而異。關鍵是,您應該批量獲取數據,而不是 SELECT * FROM X
。
OutputStream
被包裹在 GZIPOutputStream
中,因為像 JSON 這樣帶有重復元素的文本文件可以從壓縮中顯著受益
主要工作是由 Jackson 的 SequenceWriter 完成的,需要清楚的點是 - 不要假設您的數據會適合內存。它幾乎從不這樣做,因此以批處理和增量寫入的方式進行所有操作。
以上是“Java如何使用Jackson編寫大型JSON文件”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。