查看源代码 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
来更改。排序函数是反对称的、传递的和总体的。如果A
在排序中位于B
之前,则Fun(A, B)
应返回true
,否则返回false
。典型的排序函数示例是小于或等于,=</2
。使用排序函数会显著降低排序速度。函数keysort
、keymerge
和keycheck
不接受排序函数。{unique, boolean()}
- 当排序或合并文件时,如果此选项设置为true
,则仅输出比较相等(==
)的项序列中的第一个项。默认为false
,这意味着输出所有比较相等的项。当检查文件的排序时,如果此选项设置为true
,则会检查是否没有一对连续的项比较相等。{tmpdir, TempDirectory}
- 可以显式选择临时文件的存放目录。默认值(由值""
表示)是将临时文件放在与排序后的输出文件相同的目录中。如果输出是函数(请参阅下文),则使用file:get_cwd()
返回的目录。临时文件的名称来自 Erlang 节点名 (node/0
)、当前 Erlang 模拟器的进程标识符 (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().
对文件中的项进行排序。