erlang 从文件末尾的位置列出行
erlang list lines from position from end of the file
是否可以有一个函数从末尾开始 return x 行文件?该函数将采用参数来定义我们想要从末端读取多远(以行测量)以及我们想要从该位置return编辑多少行:
get_lines_file_end(IoDevice, LineNumberPositionFromEnd, LineCount) ->
示例:
我们有 30 行 0-29
的文件
get_lines_file_end(IoDevice, -10, 10) // will return lines 20-29
get_lines_file_end(IoDevice, -20, 10) // will return lines 10-19
这里的问题是我只能用 file:position 搜索一定数量的字节..
目的:
从最后 "page" 开始以页面方式查看大型日志文件(数百 MB)。
Erlang 用于 rest api,它被 javascript web 使用。
该功能的用途是逐页查看整个日志文件,其中一页由x行文本表示。不需要处理日志文件或获取其中的某些信息。
谢谢
您可以使用 file:read_line/1
function 读取行,丢弃那些与您的范围不匹配的行:
get_lines(File, From) when From > 0 ->
get_lines(File, file:read_line(File), From, 1).
get_lines(_File, eof, _From, _Current) ->
[];
get_lines(File, {ok, _Line}, From, Current) when Current < From ->
get_lines(File, file:read_line(File), From, Current + 1);
get_lines(File, {ok, Line}, From, Current) ->
[Line|get_lines(File, file:read_line(File), From, Current + 1)];
get_lines(_IoDevice, Error, _From, _Current) ->
Error.
有两点需要说明:
- 为了提高效率,您必须创建有关文本文件内容的元数据,以分摊所涉及的工作。通过这种方式,您可以在 创建此元数据后使用
file:position/2
搜索直接跳到您需要的位。
- 如果这是您的用例,那么您应该以不同的方式划分工作。巨大的文本文件应该被分解成更小的文本文件,或者(更有可能)你根本不应该使用文本文件。根据您的目标是什么(您没有提到;我强烈怀疑这是一个 X-Y 问题)您可能 根本不需要文本,而是 想知道文本所代表的东西。将原始文本保存在某个地方以防万一可能是个好主意,但对于数据的实际处理,创建符号数据几乎肯定是一个更好的主意,这些符号数据(更简短地)代表您对数据感兴趣的任何内容,并将其存储在数据库中,在数据库中查找、扫描、索引和执行您可能想要的任何其他操作都是自然操作。
要构建有关文件的元数据,您需要执行类似于以下操作的操作:
1> {ok, Data} = file:read_file("TheLongDarkTeaTimeOfTheSoul.txt").
{ok,<<"Douglas Adams. The Long Dark Tea-Time of the Soul\r\n\r\n"...>>}
2> LineEnds = binary:matches(Data, <<"\r\n">>).
[{49,2},
{51,2},
{53,2},
{...}|...]
然后将 LineEnds
作为文件本身的元数据单独保存在某个地方。在文件数据中使用这种搜索是基本的(例如,在换行符 X 或 length(LineEnds) - X
或其他位置对数据使用 file:position/2
)。
但这仍然很愚蠢。
如果您想在日志文件中跳来跳去,特别是如果您希望能够在其中找到模式,计算它们的某些方面等,那么您几乎肯定会更好地将它们读入数据库,例如Postgres 逐行计算行号。到那时,分页就成了小问题。
然而,日志文件通常充满了最好用符号表示的数据,而不是实际的文本,将日志文件标记化可能是一个更好的主意。考虑访问日志文件的情况。重复访问者从有限数量的访问点(IP 或设备,或其他)访问任意次数。这方面的每个方面都可以在数据库中单独索引和比较相当简单。标记化本身也相当微不足道。此解决方案不仅 多 快于以后的数据分析,而且它自然地有助于回答问题,否则 非常困难 回答问题以非常直接和熟悉的方式讲述数据的内容。 ...而且您甚至不必丢失任何原始数据或处理的中间阶段(它们可能都以不同的方式独立使用)。
另外...请注意,以上所有工作都可以在 Erlang 中很容易地并行进行。无论您的计算资源情况如何,编写一个最能充分利用您的硬件的解决方案肯定是可以掌握的(假设您有足够的总数据,这甚至是一个问题)。
就像许多 "How to do X with data Y?" 问题一样,真正的答案总是围绕着 "What is your goal regarding the data and why?"
是否可以有一个函数从末尾开始 return x 行文件?该函数将采用参数来定义我们想要从末端读取多远(以行测量)以及我们想要从该位置return编辑多少行:
get_lines_file_end(IoDevice, LineNumberPositionFromEnd, LineCount) ->
示例: 我们有 30 行 0-29
的文件get_lines_file_end(IoDevice, -10, 10) // will return lines 20-29
get_lines_file_end(IoDevice, -20, 10) // will return lines 10-19
这里的问题是我只能用 file:position 搜索一定数量的字节..
目的: 从最后 "page" 开始以页面方式查看大型日志文件(数百 MB)。 Erlang 用于 rest api,它被 javascript web 使用。
该功能的用途是逐页查看整个日志文件,其中一页由x行文本表示。不需要处理日志文件或获取其中的某些信息。
谢谢
您可以使用 file:read_line/1
function 读取行,丢弃那些与您的范围不匹配的行:
get_lines(File, From) when From > 0 ->
get_lines(File, file:read_line(File), From, 1).
get_lines(_File, eof, _From, _Current) ->
[];
get_lines(File, {ok, _Line}, From, Current) when Current < From ->
get_lines(File, file:read_line(File), From, Current + 1);
get_lines(File, {ok, Line}, From, Current) ->
[Line|get_lines(File, file:read_line(File), From, Current + 1)];
get_lines(_IoDevice, Error, _From, _Current) ->
Error.
有两点需要说明:
- 为了提高效率,您必须创建有关文本文件内容的元数据,以分摊所涉及的工作。通过这种方式,您可以在 创建此元数据后使用
file:position/2
搜索直接跳到您需要的位。 - 如果这是您的用例,那么您应该以不同的方式划分工作。巨大的文本文件应该被分解成更小的文本文件,或者(更有可能)你根本不应该使用文本文件。根据您的目标是什么(您没有提到;我强烈怀疑这是一个 X-Y 问题)您可能 根本不需要文本,而是 想知道文本所代表的东西。将原始文本保存在某个地方以防万一可能是个好主意,但对于数据的实际处理,创建符号数据几乎肯定是一个更好的主意,这些符号数据(更简短地)代表您对数据感兴趣的任何内容,并将其存储在数据库中,在数据库中查找、扫描、索引和执行您可能想要的任何其他操作都是自然操作。
要构建有关文件的元数据,您需要执行类似于以下操作的操作:
1> {ok, Data} = file:read_file("TheLongDarkTeaTimeOfTheSoul.txt").
{ok,<<"Douglas Adams. The Long Dark Tea-Time of the Soul\r\n\r\n"...>>}
2> LineEnds = binary:matches(Data, <<"\r\n">>).
[{49,2},
{51,2},
{53,2},
{...}|...]
然后将 LineEnds
作为文件本身的元数据单独保存在某个地方。在文件数据中使用这种搜索是基本的(例如,在换行符 X 或 length(LineEnds) - X
或其他位置对数据使用 file:position/2
)。
但这仍然很愚蠢。
如果您想在日志文件中跳来跳去,特别是如果您希望能够在其中找到模式,计算它们的某些方面等,那么您几乎肯定会更好地将它们读入数据库,例如Postgres 逐行计算行号。到那时,分页就成了小问题。
然而,日志文件通常充满了最好用符号表示的数据,而不是实际的文本,将日志文件标记化可能是一个更好的主意。考虑访问日志文件的情况。重复访问者从有限数量的访问点(IP 或设备,或其他)访问任意次数。这方面的每个方面都可以在数据库中单独索引和比较相当简单。标记化本身也相当微不足道。此解决方案不仅 多 快于以后的数据分析,而且它自然地有助于回答问题,否则 非常困难 回答问题以非常直接和熟悉的方式讲述数据的内容。 ...而且您甚至不必丢失任何原始数据或处理的中间阶段(它们可能都以不同的方式独立使用)。
另外...请注意,以上所有工作都可以在 Erlang 中很容易地并行进行。无论您的计算资源情况如何,编写一个最能充分利用您的硬件的解决方案肯定是可以掌握的(假设您有足够的总数据,这甚至是一个问题)。
就像许多 "How to do X with data Y?" 问题一样,真正的答案总是围绕着 "What is your goal regarding the data and why?"