我需要每 1000 行向文本檔案添加一行。主要問題是該檔案大約為 3GB,因此我無法將整個檔案加載到字串或陣列中。要處理大檔案,我通常使用 File.foreach 但在這種情況下我找不到有關使用索引的任何資訊。是否有任何其他選項可以解決此問題而無需將整個檔案加載到記憶體中?
uj5u.com熱心網友回復:
這里有幾個選項。
選項1:
File.open('output.txt', 'w') do |outfile|
File.foreach('input.txt').each_with_index do |line, i|
outfile.puts(line)
outfile.puts '--- 1000 ---' if (i 1) % 1000 == 0 && i != 0
end
end
'--- 1000 ---'這會在原始檔案的每 1000 行之后插入一行。雖然它有一些缺點。主要是它必須檢查每個索引并檢查我們是否不在每一行的第 0 行!但它有效。它適用于大檔案而不會占用記憶體。
選項 2:
File.open('output.txt', 'w') do |outfile|
File.foreach('input.txt').each_slice(1000) do |lines|
outfile.puts(lines)
outfile.puts '--- 1000 ---'
end
end
Enumerable這段代碼使用'seach_slice方法做了幾乎完全相同的事情。它每 1000 行生成一個陣列,使用puts(接受Arrays) 將它們寫出,然后在其后寫入我們的標記行。然后重復接下來的 1000 行。不同之處在于,如果檔案不是 1000 行的倍數,則最后一次呼叫此塊將產生一個小于 1000 行的陣列,并且我們的代碼仍將在其后附加我們的文本行。
我們可以通過測驗陣列的長度來解決這個問題,并且只有當陣列正好是 1000 行時才寫出我們的行。對于除最后一行之外的每批 1000 行(假設檔案不是 1000 行的倍數),這將是正確的。
選項 2a:
File.open('output.txt', 'w') do |outfile|
File.foreach('input.txt').each_slice(1000) do |lines|
outfile.puts(lines)
outfile.puts '--- 1000 ---' unless lines.size < 1000
end
end
僅當將該行附加到檔案末尾對您來說是一個問題時,才需要進行此額外檢查。否則,您可以將其忽略以提高性能。
說到性能,以下是每個選項在包含 1,000,000 段 Lorem Ipsum 的 335.5 MB 檔案上的執行情況。每個基準是處理整個檔案 100 次的總時間。
選項1:
103.859825 44.646519 148.506344 (152.286349)
[Finished in 152.6s]
選項 2:
96.249542 43.780160 140.029702 (145.210728)
[Finished in 145.7s]
選項 2a:
98.041073 45.788944 143.830017 (149.769698)
[Finished in 150.2s]
As you can see, option 2 is the fastest. Keep in mind, options 2/2a will in theory use more memory since it loads 1000 lines at a time, but even then it's capped at a very small level so handling enormous files shouldn't be a problem. However they are all so close I would recommend going with whatever option reads the best or makes the most sense.
Hope this helped.
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/440701.html
標籤:红宝石
