我有一個文字檔案每行一個字,檔案大小為800GB。我需要按字母順序對單字進行排序。
我嘗試過使用視窗 種類程式使用:
sort.exe input.txt /o output.txt
這給了錯誤:主記憶體不足,無法完成排序。
我有32GB記憶體因此,當我嘗試使用以下命令指定 10GB 記憶體進行排序時:
sort.exe input.txt /o output.txt /M 10000000
我得到:
警告:指定的記憶體大小正在減少到可用的分頁記憶體。
輸入記錄超過最大長度。指定更大的最大值。
我有什麼選擇?
答案1
我有什麼選擇?
它使用多個臨時文件,然後在最後合併它們。
CMsort 正在讀取輸入檔的記錄,直到達到調整後的記憶體。然後記錄被排序並寫入臨時檔案。這將重複進行,直到處理完所有記錄。最後,所有臨時檔案都合併到輸出檔案中。如果可用記憶體足夠,則不會寫入臨時文件,也不需要合併。
一位用戶報告說它對 130,000,000 位元組的檔案進行了排序。
如果您想自己調整一些程式碼,也可以對巨大的文字檔案進行排序 - CodeProject- “對大小超過可用記憶體的文字檔案中的行進行排序的演算法”
答案2
另一種選擇是將文件載入到資料庫中。例如 MySQL 和 MySQL Workbench。
資料庫是處理大檔案的完美選擇。
如果您的輸入檔案僅包含由換行符號分隔的單詞,那麼這應該不會太難。
安裝資料庫和 MySQL Workbench 後,您需要執行下列操作。
首先,建立架構(這假設單字長度不會超過 255 個字符,儘管您可以透過增加參數值來更改此設定)。
第一列“idwords”是主鍵。
CREATE SCHEMA `tmp` ;
CREATE TABLE `tmp`.`words` (
`idwords` INT NOT NULL AUTO_INCREMENT,
`mywords` VARCHAR(255) NULL,
PRIMARY KEY (`idwords`));
其次,導入資料。
例如,這會將所有單字匯入表中;此步驟可能需要一段時間才能完成。我的建議是首先使用較小的文件運行測試,一旦確定格式與較大的文件相同(截斷表......即清除它並加載完整的數據集)。
LOAD DATA LOCAL INFILE "C:\\words.txt" INTO TABLE tmp.words
LINES TERMINATED BY '\r\n'
(mywords);
此連結可能有助於取得適合負載的格式。 https://dev.mysql.com/doc/refman/5.7/en/load-data.html
例如,如果您需要跳過第一行,您可以執行以下操作。
LOAD DATA LOCAL INFILE "H:\\words.txt" INTO TABLE tmp.words
-- FIELDS TERMINATED BY ','
LINES TERMINATED BY '\r\n'
IGNORE 1 LINES
(mywords);
最後,儲存排序後的文件。這可能需要一段時間,具體取決於您的電腦。
SELECT tmp.words.mywords
FROM tmp.words
order by tmp.words.mywords asc
INTO OUTFILE 'C:\\sorted_words.csv';
您也可以隨意搜尋資料。
例如,這將為您提供按升序排列的前 50 個單字(從零位置或第一個單字開始)。
SELECT tmp.words.mywords
FROM tmp.words
order by tmp.words.mywords asc
LIMIT 0, 50 ;
答案3
sort
有許多演算法用於對有序和非有序文件進行排序[1]。
由於所有這些演算法都已經實現,因此選擇一個已經測試過的程式。
在核心工具 (來自 Linux,但也適用於 Windows [2]),存在sort
能夠在多核心處理器下並行運行的命令:通常就足夠了。
如果你的文件是這麼大您可以協助處理分割(split -l
),將檔案分成一些區塊,可能使用並行選項(--parallel
),並對結果進行排序有序列與-m
選項(歸併排序)。
解釋了多種方法之一這裡(分割檔案、排序單一區塊、合併排序區塊、刪除暫存檔案)。
筆記:
- 在Windows 10中存在所謂的Linux 的 Windows 子系統其中所有的Linux 範例都會顯得更加自然。
- 使用不同演算法進行排序具有不同的執行時間,其執行時間根據要排序的資料條目的數量而變化(O(n m )、O(nlogn)...)。
- 演算法的效率取決於原始文件中已存在的順序。
(例如冒泡排序是對於已排序的檔案來說最快的演算法(恰好是 N),但在其他情況下效率不高)。
答案4
如果每行上的單字來自有限的詞彙(例如英語),那麼您可以使用 TreeMap 並記錄計數(其中 m 是唯一值的數量)在 O(n + m log m) 時間內對清單進行排序。
否則你可以使用java庫大分類機。它將輸入拆分為排序的中間文件並有效地合併它們(總體 O(nlogn))。要對文件進行排序,如下所示:
Sorter.serializerTextUtf8()
.input(inputFile)
.output(outputFile)
.loggerStdOut() // display some progress
.sort();
我創建了一個1.7GB 檔案(100m 行),隨機生成16 個字元單詞,並在142 秒內按照上述方式對其進行排序,並且基於我正在使用的方法的O(n log n) 計算複雜度,我估計800GB 的16 個字元單字將在我配備 SSD 的 i5 2.3GHz 筆記型電腦上進行單線程排序大約需要 24 小時。