查看源代码 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,这意味着二进制数据将按原样排序。这是最快的格式。如果 Formatterm,则调用 io:read/2 来读取项。在这种情况下,只允许使用选项 header 的默认值。

    选项 format 还确定写入排序后的输出文件的内容:如果 Formatterm,则调用 io:format/3 来写入每个项,否则写入带有头部的二进制数据。 请注意,写入的二进制数据与读取的二进制数据相同;当项被排序后,应用函数 Format 的结果将被丢弃。使用 io 模块读取和写入项比读取和写入二进制数据慢得多。

其他选项有:

  • {order, Order} - 默认情况下,项按升序排序,但可以通过值 descending 或指定排序函数 Fun 来更改。排序函数是反对称的、传递的和总体的。如果 A 在排序中位于 B 之前,则 Fun(A, B) 应返回 true,否则返回 false。典型的排序函数示例是小于或等于,=</2。使用排序函数会显著降低排序速度。函数 keysortkeymergekeycheck 不接受排序函数。

  • {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 是一个新的输入函数。

任何其他值都会立即作为当前对 sortkeysort 的调用的值返回。每个输入函数都只调用一次。如果发生错误,则使用参数 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 比较下一个元素。排序是稳定的。

合并文件中的项。假设每个输入文件都已排序。

对文件中的项进行排序。

对文件中的项进行排序。

类型

链接到此类型

file_name()

查看源代码 (未导出)
-type file_name() :: file:name().
链接到此类型

file_names()

查看源代码 (未导出)
-type file_names() :: [file:name()].
链接到此类型

format()

查看源代码 (未导出)
-type format() :: binary_term | term | binary | format_fun().
链接到此类型

format_fun()

查看源代码 (未导出)
-type format_fun() :: fun((binary()) -> term()).
链接到此类型

header_length()

查看源代码 (未导出)
-type header_length() :: pos_integer().
链接到此类型

i_command()

查看源代码 (未导出)
-type i_command() :: read | close.
链接到此类型

i_reply()

查看源代码 (未导出)
-type i_reply() :: end_of_input | {end_of_input, value()} | {[object()], infun()} | input_reply().
-type infun() :: fun((i_command()) -> i_reply()).
-type input() :: file_names() | infun().
链接到此类型

input_reply()

查看源代码 (未导出)
-type input_reply() :: term().
链接到此类型

key_pos()

查看源代码 (未导出)
-type key_pos() :: pos_integer() | [pos_integer()].
链接到此类型

no_files()

查看源代码 (未导出)
-type no_files() :: pos_integer().
链接到此类型

o_command()

查看源代码 (未导出)
-type o_command() :: {value, value()} | [object()] | close.
链接到此类型

o_reply()

查看源代码 (未导出)
-type o_reply() :: outfun() | output_reply().
链接到此类型

object()

查看源代码 (未导出)
-type object() :: term() | binary().
链接到此类型

option()

查看源代码 (未导出)
-type option() ::
          {compressed, boolean()} |
          {header, header_length()} |
          {format, format()} |
          {no_files, no_files()} |
          {order, order()} |
          {size, size()} |
          {tmpdir, tmp_directory()} |
          {unique, boolean()}.
链接到此类型

options()

查看源代码 (未导出)
-type options() :: [option()] | option().
-type order() :: ascending | descending | order_fun().
链接到此类型

order_fun()

查看源代码 (未导出)
-type order_fun() :: fun((term(), term()) -> boolean()).
链接到此类型

outfun()

查看源代码 (未导出)
-type outfun() :: fun((o_command()) -> o_reply()).
链接到此类型

output()

查看源代码 (未导出)
-type output() :: file_name() | outfun().
链接到此类型

output_reply()

查看源代码 (未导出)
-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().
链接到此类型

tmp_directory()

查看源代码 (未导出)
-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().

等效于 check([FileName], [])

链接到此函数

check(FileNames, Options)

查看源代码
-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。

链接到此函数

keycheck(KeyPos, FileName)

查看源代码
-spec keycheck(KeyPos, FileName) -> Reply
                  when
                      KeyPos :: key_pos(),
                      FileName :: file_name(),
                      Reply :: {ok, [Result]} | {error, reason()},
                      Result :: {FileName, TermPosition, term()},
                      TermPosition :: pos_integer().

等效于 keycheck(KeyPos, [Filename], [])

链接到此函数

keycheck(KeyPos, FileNames, Options)

查看源代码
-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。

链接到此函数

keymerge(KeyPos, FileNames, Output)

查看源代码
-spec keymerge(KeyPos, FileNames, Output) -> Reply
                  when
                      KeyPos :: key_pos(),
                      FileNames :: file_names(),
                      Output :: output(),
                      Reply :: ok | {error, reason()} | output_reply().

等效于 keymerge(KeyPos, FileNames, Output, [])

链接到此函数

keymerge(KeyPos, FileNames, Output, Options)

查看源代码
-spec keymerge(KeyPos, FileNames, Output, Options) -> Reply
                  when
                      KeyPos :: key_pos(),
                      FileNames :: file_names(),
                      Output :: output(),
                      Options :: options(),
                      Reply :: ok | {error, reason()} | output_reply().

合并文件中的元组。假设每个输入文件都按键排序。

链接到此函数

keysort(KeyPos, FileName)

查看源代码
-spec keysort(KeyPos, FileName) -> Reply
                 when
                     KeyPos :: key_pos(),
                     FileName :: file_name(),
                     Reply :: ok | {error, reason()} | input_reply() | output_reply().

对文件中的元组进行排序。

链接到此函数

keysort(KeyPos, Input, Output)

查看源代码
-spec keysort(KeyPos, Input, Output) -> Reply
                 when
                     KeyPos :: key_pos(),
                     Input :: input(),
                     Output :: output(),
                     Reply :: ok | {error, reason()} | input_reply() | output_reply().

等效于 keysort(KeyPos, Input, Output, [])

链接到此函数

keysort(KeyPos, Input, Output, Options)

查看源代码
-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 比较下一个元素。排序是稳定的。

链接到此函数

merge(FileNames, Output)

查看源代码
-spec merge(FileNames, Output) -> Reply
               when
                   FileNames :: file_names(),
                   Output :: output(),
                   Reply :: ok | {error, reason()} | output_reply().

等效于 merge(FileNames, Output, [])

链接到此函数

merge(FileNames, Output, Options)

查看源代码
-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().

等效于 sort(Input, Output, [])

链接到此函数

sort(Input, Output, Options)

查看源代码
-spec sort(Input, Output, Options) -> Reply
              when
                  Input :: input(),
                  Output :: output(),
                  Options :: options(),
                  Reply :: ok | {error, reason()} | input_reply() | output_reply().

对文件中的项进行排序。