在 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

文件:

key_1=val_1
key_2=val_2
key_3=val_3
/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 个元素的列表,因此匹配失败。

要解决这个问题...

  1. 我们可以更改 keyvalue.properties 的格式,使每一行都是有效的 key-value 对,但不确定它在程序上下文中的可行性。
  2. 或者,我们可以更改 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