在 Erlang 中读取文件
Reading files in Erlang
我有一个 Erlang 应用程序可以从文件中获取一些 key/value 对。
在其中一个文件中,我有一个指向不同文件夹的路径,而不是 key/value 对,其中有 key/value 对。
文件读取工作正常,但每当我必须从文件读取路径然后读取后续文件时,应用程序会抱怨该文件不存在。
如果我跳进容器查看,可以看到文件和后续文件。所以我想我错过了什么。
这是我的:
get_kvs("keyvalue.properties"), %% <-- This works
{ok, PathToFile} = file:read_file("pathtofile.properties"),
get_kvs(PathToFile), %% <-- This crashes
文件:
keyvalue.properties
:
key_1=val_1
key_2=val_2
key_3=val_3
pathtofile.properties
:
/data/myfolder/hidden_keyvalue.properties
/data/myfolder/hidden_keyvalue.properties
:
extra_key1=extra_val1
extra_key2=extra_val2
extra_key3=extra_val3
和 get_metadata
函数:
get_metadata(FileName) ->
io:format(FileName),
{ok, MetadataFile} = file:read_file(FileName),
io:format(MetadataFile),
Lines = binary:split(MetadataFile, <<"\n">>, [trim, global]),
make_tuples(Lines, []).
make_tuples([Line|Lines], Acc) ->
[Key, Value] = binary:split(Line, <<"=">>),
make_tuples(Lines, [{Key, Value}|Acc]);
make_tuples([], Acc) -> lists:reverse(Acc).
每当 运行 时,我都可以看到 PathToFile
已正确填充,但是当我尝试读取路径时,出现以下错误:
keyvalue.propertiesextra_key_1=extra_val_1
extra_key_2=extra_val_2
extra_key_3=extra_val_3
/data/myfolder/hidden_keyvalue.properties
=CRASH REPORT==== 23-Mar-2022::07:46:30.612093 ===
crasher:
initial call: cowboy_stream_h:request_process/3
pid: <0.735.0>
registered_name: []
exception error: no match of right hand side value {error,enoent}
in function hello_handler:get_metadata/1 (/data/apps/hello_server/src/hello_handler.erl, line 40)
in call from hello_handler:child_call/1 (/data/apps/hello_server/src/hello_handler.erl, line 28)
知道我遗漏了什么吗?
通过删除 try-catch
修改 OP 以反映实际故障点后,错误似乎是 {error, enoent }
,这意味着 The file does not exist
。但是,相同的功能在某些情况下有效,而不是当要读取的文件的路径本身取自另一个文件时。
只需确保文件内容后有 mo 个附加字符,如换行符或 non-printable 个字符,这实际上应该是一个有效路径。
例如,当我尝试使用这样的值时,<<"hidden_keyvalue.properties\n\n">>
,然后 read_file
给了我与 {error, enoent}
相同的结果。
因此,读取路径的文件内容可能在末尾有额外的 non-printable 个字符。
忽略(错误假设)
我尝试使用本地设置,我认为 make_tuples
中的这一行导致了这种行为。
[Key, Value] = binary:split(Line, <<"=">>) %% <--- This match will succeed only if there are exactly 2 elements in the list produced by binary:split(...).
鉴于我们在里面做 get_metadata
Lines = binary:split(MetadataFile, <<"\n">>, [trim, global]), %% <-- This splits the contents of the keyvalue.properties file into a List
make_tuples(Lines, [])
从提供的文本来看,keyvalue.proiperties
文件的内容似乎是...
key_1=val_1
key_2=val_2
key_3=val_3
/data/myfolder/hidden_keyvalue.properties %% <-- This isn't a valid key-value pair
对于最后一行,make_tuples
在进行匹配时将以下列方式失败...
[Key, Value] = binary:split(<<"/data/myfolder/hidden_keyvalue.properties">>, <<"=">>).
** exception error: no match of right hand side value [<<"/data/myfolder/hidden_keyvalue.properties">>]
pattern-match 表达式在 right-hand 侧(Term/Value 侧)正好需要 2 个元素。由于 keyvalue.properties
中带有 path-entry 的行没有 =
,因此拆分会生成一个包含 1 个元素的列表,因此匹配失败。
要解决这个问题...
- 我们可以更改
keyvalue.properties
的格式,使每一行都是有效的 key-value
对,但不确定它在程序上下文中的可行性。
- 或者,我们可以更改 pattern-match 形式的列表,以便它在匹配时可以接受 non-exact 个词项
make_tuples([Line|Lines], Acc) ->
%% [Key|Value] is at least 1 element list, [Key, Value] is exactly 2 elements list
[Key|Value] = binary:split(Line, <<"=">>), %% <-- Now Value becomes a list of binary
make_tuples(Lines, [{Key, get_value(Value)}|Acc]); %% <-- Additional get_value function to extract 'Value binary' from the head of the 'Value List' produced in the previous line
make_tuples([], Acc) -> lists:reverse(Acc).
get_value([]) ->
<<>>;
get_value([V|_]) -> V.
假设
get_kvs
invokes get_metadata
which in turn invokes make_tuples
.
keyvalue.properties
file content has both valid key-value pairs and also some non-key-value entries
我有一个 Erlang 应用程序可以从文件中获取一些 key/value 对。
在其中一个文件中,我有一个指向不同文件夹的路径,而不是 key/value 对,其中有 key/value 对。
文件读取工作正常,但每当我必须从文件读取路径然后读取后续文件时,应用程序会抱怨该文件不存在。
如果我跳进容器查看,可以看到文件和后续文件。所以我想我错过了什么。
这是我的:
get_kvs("keyvalue.properties"), %% <-- This works
{ok, PathToFile} = file:read_file("pathtofile.properties"),
get_kvs(PathToFile), %% <-- This crashes
文件:
keyvalue.properties
:
key_1=val_1
key_2=val_2
key_3=val_3
pathtofile.properties
:
/data/myfolder/hidden_keyvalue.properties
/data/myfolder/hidden_keyvalue.properties
:
extra_key1=extra_val1
extra_key2=extra_val2
extra_key3=extra_val3
和 get_metadata
函数:
get_metadata(FileName) ->
io:format(FileName),
{ok, MetadataFile} = file:read_file(FileName),
io:format(MetadataFile),
Lines = binary:split(MetadataFile, <<"\n">>, [trim, global]),
make_tuples(Lines, []).
make_tuples([Line|Lines], Acc) ->
[Key, Value] = binary:split(Line, <<"=">>),
make_tuples(Lines, [{Key, Value}|Acc]);
make_tuples([], Acc) -> lists:reverse(Acc).
每当 运行 时,我都可以看到 PathToFile
已正确填充,但是当我尝试读取路径时,出现以下错误:
keyvalue.propertiesextra_key_1=extra_val_1
extra_key_2=extra_val_2
extra_key_3=extra_val_3
/data/myfolder/hidden_keyvalue.properties
=CRASH REPORT==== 23-Mar-2022::07:46:30.612093 ===
crasher:
initial call: cowboy_stream_h:request_process/3
pid: <0.735.0>
registered_name: []
exception error: no match of right hand side value {error,enoent}
in function hello_handler:get_metadata/1 (/data/apps/hello_server/src/hello_handler.erl, line 40)
in call from hello_handler:child_call/1 (/data/apps/hello_server/src/hello_handler.erl, line 28)
知道我遗漏了什么吗?
通过删除 try-catch
修改 OP 以反映实际故障点后,错误似乎是 {error, enoent }
,这意味着 The file does not exist
。但是,相同的功能在某些情况下有效,而不是当要读取的文件的路径本身取自另一个文件时。
只需确保文件内容后有 mo 个附加字符,如换行符或 non-printable 个字符,这实际上应该是一个有效路径。
例如,当我尝试使用这样的值时,<<"hidden_keyvalue.properties\n\n">>
,然后 read_file
给了我与 {error, enoent}
相同的结果。
因此,读取路径的文件内容可能在末尾有额外的 non-printable 个字符。
忽略(错误假设)
我尝试使用本地设置,我认为 make_tuples
中的这一行导致了这种行为。
[Key, Value] = binary:split(Line, <<"=">>) %% <--- This match will succeed only if there are exactly 2 elements in the list produced by binary:split(...).
鉴于我们在里面做 get_metadata
Lines = binary:split(MetadataFile, <<"\n">>, [trim, global]), %% <-- This splits the contents of the keyvalue.properties file into a List
make_tuples(Lines, [])
从提供的文本来看,keyvalue.proiperties
文件的内容似乎是...
key_1=val_1
key_2=val_2
key_3=val_3
/data/myfolder/hidden_keyvalue.properties %% <-- This isn't a valid key-value pair
对于最后一行,make_tuples
在进行匹配时将以下列方式失败...
[Key, Value] = binary:split(<<"/data/myfolder/hidden_keyvalue.properties">>, <<"=">>).
** exception error: no match of right hand side value [<<"/data/myfolder/hidden_keyvalue.properties">>]
pattern-match 表达式在 right-hand 侧(Term/Value 侧)正好需要 2 个元素。由于 keyvalue.properties
中带有 path-entry 的行没有 =
,因此拆分会生成一个包含 1 个元素的列表,因此匹配失败。
要解决这个问题...
- 我们可以更改
keyvalue.properties
的格式,使每一行都是有效的key-value
对,但不确定它在程序上下文中的可行性。 - 或者,我们可以更改 pattern-match 形式的列表,以便它在匹配时可以接受 non-exact 个词项
make_tuples([Line|Lines], Acc) ->
%% [Key|Value] is at least 1 element list, [Key, Value] is exactly 2 elements list
[Key|Value] = binary:split(Line, <<"=">>), %% <-- Now Value becomes a list of binary
make_tuples(Lines, [{Key, get_value(Value)}|Acc]); %% <-- Additional get_value function to extract 'Value binary' from the head of the 'Value List' produced in the previous line
make_tuples([], Acc) -> lists:reverse(Acc).
get_value([]) ->
<<>>;
get_value([V|_]) -> V.
假设
get_kvs
invokesget_metadata
which in turn invokesmake_tuples
.
keyvalue.properties
file content has both valid key-value pairs and also some non-key-value entries