簡體   English   中英

如何從一個巨大的文件中讀取任意但連續的n行

[英]How to read arbitrary but continuous n lines from a huge file

我想閱讀任意數量的行。 目前,這些文件是普通的ascii文本文件(以后可能是UTF8 /多字節字符文件)

因此,我想要的是一種僅讀取特定行的文件的方法(例如,從101-200開始),並且這樣做時,它不應阻止任何事情(即同一文件可以被201-210的另一個線程讀取,並且不應該等待第一次讀取操作。

在沒有要讀取的行的情況下,它應該優雅地返回它可以讀取的內容。 方法的輸出可以是一個列表

到目前為止,我想到的解決方案是先讀取整個文件,以找到行數以及每個新行字符的字節位置。 然后使用RandomAccessFile讀取字節並將其轉換為行。 我必須將字節轉換為字符串(但是可以在完成讀取之后完成)。 我會避免通過適當的記賬來讀取超出文件范圍的文件末尾異常。 該解決方案效率不高,因為它確實會遍歷兩次文件,但是文件大小可能確實很大,並且我們希望在內存中保留很少的空間。

如果有一個適用於這種情況的庫,但是更簡單的本機Java解決方案將是不錯的選擇。

一如既往,我感謝您提出的澄清問題,我們將隨時對此問題進行編輯。

為什么不使用Scanner並循環遍歷hasNextLine()直到達到所需的計數,然后抓取盡可能多的行...如果用完了,它將優雅地失敗。 這樣,您只需要讀取一次文件(除非Scanner可以完全讀取它...我從未看過幕后故事...但是聽起來好像並不在乎您的意思,所以...就這樣:)

如果要最小化內存消耗,我將使用內存映射文件。 這幾乎不使用堆。 操作系統會處理內存中保留的文件量,因此您無需自己調整行為。

FileChannel fc = new FileInputStream(fileName).getChannel();
final MappedByteBuffer map = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());

如果文件大小為2 GB或更大,則需要多個映射。 在最簡單的情況下,您可以掃描數據並記住所有索引。 他們擁有的索引可能占用大量空間,因此您可能只記得每N個,例如十分之一。

例如,具有40個字節行的2 GB文件可能具有5000萬行,需要400 MB的內存。

具有較大索引的另一種方法是創建另一個內存映射文件。

FileChannel fc = new RandomAccessFile(fileName).getChannel();
final MappedByteBuffer map2 = fc.map(FileChannel.MapMode.READ_WRITE, 0, fc.size()/10);

問題是,您不知道開始前文件的大小。 幸運的是,如果將其增大到所需的大小,則不會消耗內存或磁盤空間,因此最簡單的操作是將其增大並在知道所需大小時將其截斷。

這也可以用來避免在每次加載文件時重新索引文件(僅在更改文件時)。如果僅將文件附加到文件,則可以每次從文件末尾索引。

注意:使用這種方法會占用大量虛擬內存,對於64位JVM,這沒有問題,因為您的限制可能為256 TB。 對於32位應用程序,根據您的操作系統,您的限制可能為1.5-3.5 GB。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM