檢視原始碼 file_sorter (stdlib v6.2)
檔案排序器。
此模組包含在檔案上排序詞語、合併已排序檔案和檢查檔案是否已排序的功能。包含二進位詞語的區塊會從一系列檔案中讀取,在記憶體中進行內部排序,並寫入暫存檔,然後合併這些暫存檔以產生一個已排序的輸出檔。合併是一種最佳化方法;當檔案已經排序時速度更快,但它始終可以執行排序而非合併。
在檔案中,一個詞語由標頭和二進位表示。有兩個選項定義檔案中詞語的格式:
{header, HeaderLength}
-HeaderLength
決定每個二進位之前的前導位元組數,其中包含二進位的位元組長度。預設值為 4。標頭位元組的順序定義如下:如果B
是僅包含標頭的二進位,則二進位的大小Size
計算為<<Size:HeaderLength/unit:8>> = B
。{format, Format}
- 選項Format
決定套用於二進位以建立要排序的詞語的函式。預設值為binary_term
,相當於fun binary_to_term/1
。值binary
相當於fun(X) -> X end
,這表示二進位會按照原樣排序。這是最快的格式。如果Format
是term
,則會呼叫io:read/2
來讀取詞語。在這種情況下,僅允許選項header
的預設值。選項
format
也會決定要寫入已排序輸出檔的內容:如果Format
是term
,則會呼叫io:format/3
來寫入每個詞語,否則會寫入以標頭作為前綴的二進位。請注意,寫入的二進位與讀取的二進位相同;當詞語排序完成後,會捨棄套用函式Format
的結果。使用io
模組讀取和寫入詞語的速度遠低於讀取和寫入二進位。
其他選項包括:
{order, Order}
- 預設為以遞增順序排序詞語,但是可以使用值descending
或指定排序函式Fun
來變更此行為。排序函式必須是反對稱、傳遞和完全的。Fun(A, B)
如果A
在排序中位於B
之前,則必須傳回true
,否則傳回false
。典型的排序函式範例是小於或等於,=</2
。使用排序函式會大幅降低排序速度。函式keysort
、keymerge
和keycheck
不接受排序函式。{unique, boolean()}
- 排序或合併檔案時,如果此選項設定為true
,則僅輸出比較相等的 (==
) 一連串詞語中的第一個。預設值為false
,表示會輸出所有比較相等的詞語。檢查檔案是否已排序時,如果此選項設定為true
,則會執行檢查,確保沒有連續的詞語對比較相等。{tmpdir, TempDirectory}
- 可以明確選擇暫存檔的放置目錄。預設值,即值""
所表示的,是將暫存檔放置在與已排序輸出檔相同的目錄中。如果輸出是函式(請參閱下文),則會改為使用file:get_cwd()
傳回的目錄。暫存檔的名稱衍生自 Erlang 節點名稱 (node/0
)、目前 Erlang 模擬器的程序 ID (os:getpid()
) 和唯一的整數 (erlang:unique_integer([positive])
)。典型的名稱為fs_mynode@myhost_1763_4711.17
,其中17
是序號。現有檔案會被覆寫。除非發生某些未捕獲的EXIT
訊號,否則會刪除暫存檔。{compressed, boolean()}
- 可以壓縮暫存檔和輸出檔。預設值為false
,表示寫入的檔案不會壓縮。無論選項compressed
的值為何,始終可以讀取壓縮的檔案。請注意,讀取和寫入壓縮的檔案的速度明顯慢於讀取和寫入未壓縮的檔案。{size, Size}
- 預設情況下,從檔案讀取的約 512*1024 個位元組會在內部排序。這個選項很少需要。{no_files, NoFiles}
- 預設情況下,一次合併 16 個檔案。這個選項很少需要。
作為排序檔案的替代方法,可以指定一個參數的函式作為輸入。當使用參數 read
呼叫時,假設函式會傳回下列其中一項:
end_of_input
或{end_of_input, Value}}
,表示沒有更多輸入(下文將說明Value
)。{Objects, Fun}
,其中Objects
是二進位或詞語的清單,具體取決於格式,而Fun
是一個新的輸入函式。
任何其他值都會立即傳回為目前對 sort
或 keysort
呼叫的值。每個輸入函式都會恰好呼叫一次。如果發生錯誤,則會使用引數 close
呼叫最後一個函式,其回覆會被忽略。
可以指定一個參數的函式作為輸出。排序或合併輸入的結果會收集在一個非空的變長清單序列中,清單中的內容是二進位或詞語,具體取決於格式。會一次使用一個清單呼叫輸出函式,並假設其會傳回一個新的輸出函式。任何其他傳回值都會立即傳回為目前對排序或合併函式的呼叫值。每個輸出函式都會恰好呼叫一次。當某些輸出函式已套用於所有結果或發生錯誤時,會使用引數 close
呼叫最後一個函式,並傳回回覆作為目前對排序或合併函式的呼叫值。
如果指定函式作為輸入,並且最後一個輸入函式傳回 {end_of_input, Value}
,則會使用引數 {value, Value}
呼叫指定為輸出的函式。這使得能夠輕易使用輸入函式計算的值來起始輸出函式的序列。
舉例來說,假設您要排序磁碟記錄檔上的詞語。一個從磁碟記錄讀取區塊並傳回二進位清單的函式會用作輸入。結果會收集在詞語清單中。
sort(Log) ->
{ok, _} = disk_log:open([{name,Log}, {mode,read_only}]),
Input = input(Log, start),
Output = output([]),
Reply = file_sorter:sort(Input, Output, {format,term}),
ok = disk_log:close(Log),
Reply.
input(Log, Cont) ->
fun(close) ->
ok;
(read) ->
case disk_log:chunk(Log, Cont) of
{error, Reason} ->
{error, Reason};
{Cont2, Terms} ->
{Terms, input(Log, Cont2)};
{Cont2, Terms, _Badbytes} ->
{Terms, input(Log, Cont2)};
eof ->
end_of_input
end
end.
output(L) ->
fun(close) ->
lists:append(lists:reverse(L));
(Terms) ->
output([Terms | L])
end.
如需有關將函式用作輸入和輸出的更多範例,請參閱 file_sorter
模組的末尾;term
格式是使用函式來實作的。
發生錯誤時傳回的 Reason
可能值為:
bad_object
、{bad_object, FileName}
- 套用格式函式至某些二進位失敗,或無法從某些詞語中擷取鍵。{bad_term, FileName}
-io:read/2
無法讀取某些詞語。{file_error, FileName, file:posix()}
- 如需file:posix()
的說明,請參閱file
。{premature_eof, FileName}
- 在某些二進位詞語內遇到檔案結尾。
摘要
函式
檢查檔案是否已排序。如果檔案未排序,則會傳回第一個順序錯誤的元素。檔案中的第一個詞語的位置為 1。
檢查檔案是否已排序。如果檔案未排序,則會傳回第一個順序錯誤的元素。檔案中的第一個詞語的位置為 1。
合併檔案上的元組。假設每個輸入檔案都按鍵排序。
排序檔案上的元組。
排序檔案上的元組。排序是在 KeyPos
中提及的元素上執行。如果兩個元組在一個元素上比較相等 (==
),則會比較根據 KeyPos
的下一個元素。排序是穩定的。
合併檔案上的詞語。假設每個輸入檔案都已排序。
排序檔案上的詞語。
排序檔案上的詞語。
類型
-type file_name() :: file:name().
-type file_names() :: [file:name()].
-type format() :: binary_term | term | binary | format_fun().
-type header_length() :: pos_integer().
-type i_command() :: read | close.
-type i_reply() :: end_of_input | {end_of_input, value()} | {[object()], infun()} | input_reply().
-type input() :: file_names() | infun().
-type input_reply() :: term().
-type key_pos() :: pos_integer() | [pos_integer()].
-type no_files() :: pos_integer().
-type o_reply() :: outfun() | output_reply().
-type option() :: {compressed, boolean()} | {header, header_length()} | {format, format()} | {no_files, no_files()} | {order, order()} | {size, size()} | {tmpdir, tmp_directory()} | {unique, boolean()}.
-type order() :: ascending | descending | order_fun().
-type output_reply() :: term().
-type reason() :: bad_object | {bad_object, file_name()} | {bad_term, file_name()} | {file_error, file_name(), file:posix() | badarg | system_limit} | {premature_eof, file_name()}.
-type size() :: non_neg_integer().
-type tmp_directory() :: [] | file:name().
-type value() :: term().
函式
-spec check(FileName) -> Reply when FileName :: file_name(), Reply :: {ok, [Result]} | {error, reason()}, Result :: {FileName, TermPosition, term()}, TermPosition :: pos_integer().
-spec check(FileNames, Options) -> Reply when FileNames :: file_names(), Options :: options(), Reply :: {ok, [Result]} | {error, reason()}, Result :: {FileName, TermPosition, term()}, FileName :: file_name(), TermPosition :: pos_integer().
檢查檔案是否已排序。如果檔案未排序,則會傳回第一個順序錯誤的元素。檔案中的第一個詞語的位置為 1。
-spec keycheck(KeyPos, FileName) -> Reply when KeyPos :: key_pos(), FileName :: file_name(), Reply :: {ok, [Result]} | {error, reason()}, Result :: {FileName, TermPosition, term()}, TermPosition :: pos_integer().
-spec keycheck(KeyPos, FileNames, Options) -> Reply when KeyPos :: key_pos(), FileNames :: file_names(), Options :: options(), Reply :: {ok, [Result]} | {error, reason()}, Result :: {FileName, TermPosition, term()}, FileName :: file_name(), TermPosition :: pos_integer().
檢查檔案是否已排序。如果檔案未排序,則會傳回第一個順序錯誤的元素。檔案中的第一個詞語的位置為 1。
-spec keymerge(KeyPos, FileNames, Output) -> Reply when KeyPos :: key_pos(), FileNames :: file_names(), Output :: output(), Reply :: ok | {error, reason()} | output_reply().
-spec keymerge(KeyPos, FileNames, Output, Options) -> Reply when KeyPos :: key_pos(), FileNames :: file_names(), Output :: output(), Options :: options(), Reply :: ok | {error, reason()} | output_reply().
合併檔案上的元組。假設每個輸入檔案都按鍵排序。
-spec keysort(KeyPos, FileName) -> Reply when KeyPos :: key_pos(), FileName :: file_name(), Reply :: ok | {error, reason()} | input_reply() | output_reply().
排序檔案上的元組。
-spec keysort(KeyPos, Input, Output) -> Reply when KeyPos :: key_pos(), Input :: input(), Output :: output(), Reply :: ok | {error, reason()} | input_reply() | output_reply().
-spec keysort(KeyPos, Input, Output, Options) -> Reply when KeyPos :: key_pos(), Input :: input(), Output :: output(), Options :: options(), Reply :: ok | {error, reason()} | input_reply() | output_reply().
排序檔案上的元組。排序是在 KeyPos
中提及的元素上執行。如果兩個元組在一個元素上比較相等 (==
),則會比較根據 KeyPos
的下一個元素。排序是穩定的。
-spec merge(FileNames, Output) -> Reply when FileNames :: file_names(), Output :: output(), Reply :: ok | {error, reason()} | output_reply().
-spec merge(FileNames, Output, Options) -> Reply when FileNames :: file_names(), Output :: output(), Options :: options(), Reply :: ok | {error, reason()} | output_reply().
合併檔案上的詞語。假設每個輸入檔案都已排序。
-spec sort(FileName) -> Reply when FileName :: file_name(), Reply :: ok | {error, reason()} | input_reply() | output_reply().
排序檔案上的詞語。
-spec sort(Input, Output) -> Reply when Input :: input(), Output :: output(), Reply :: ok | {error, reason()} | input_reply() | output_reply().
-spec sort(Input, Output, Options) -> Reply when Input :: input(), Output :: output(), Options :: options(), Reply :: ok | {error, reason()} | input_reply() | output_reply().
排序檔案上的詞語。