【发布时间】:2009-08-03 12:30:09
【问题描述】:
我需要将数据放入文件中,因为我的其他函数需要一个文件作为输入。
如何在 Erlang 中创建唯一的文件名?
是否存在类似 unix "tempfile" 的东西?
【问题讨论】:
我需要将数据放入文件中,因为我的其他函数需要一个文件作为输入。
如何在 Erlang 中创建唯一的文件名?
是否存在类似 unix "tempfile" 的东西?
【问题讨论】:
我终于遇到了这个问题——而且我的用户同时使用 Windows 和 Linux 系统,所以老的久经考验的 lib:nonl(os:cmd("mktemp")) 方法不再适用了。
这就是我处理它的方法,既使用返回可使用文件名的mktemp/1 函数,也使用返回目录(创建后)的mktemp_dir/1 函数。
-spec mktemp(Prefix) -> Result
when Prefix :: string(),
Result :: {ok, TempFile :: file:filename()}
| {error, Reason :: file:posix()}.
mktemp(Prefix) ->
Rand = integer_to_list(binary:decode_unsigned(crypto:strong_rand_bytes(8)), 36),
TempPath = filename:basedir(user_cache, Prefix),
TempFile = filename:join(TempPath, Rand),
Result1 = filelib:ensure_dir(TempFile),
Result2 = file:write_file(TempFile, <<>>),
case {Result1, Result2} of
{ok, ok} -> {ok, TempFile};
{ok, Error} -> Error;
{Error, _} -> Error
end.
以及目录版本:
-spec mktemp_dir(Prefix) -> Result
when Prefix :: string(),
Result :: {ok, TempDir :: file:filename()}
| {error, Reason :: file:posix()}.
mktemp_dir(Prefix) ->
Rand = integer_to_list(binary:decode_unsigned(crypto:strong_rand_bytes(8)), 36),
TempPath = filename:basedir(user_cache, Prefix),
TempDir = filename:join(TempPath, Rand),
Result1 = filelib:ensure_dir(TempDir),
Result2 = file:make_dir(TempDir),
case {Result1, Result2} of
{ok, ok} -> {ok, TempDir};
{ok, Error} -> Error;
{Error, _} -> Error
end.
这两者的作用基本相同:我们得到一个高度随机的二进制名称,将其转换为 base36 字符串,并将其附加到操作系统返回给我们的任何内容,作为安全的用户本地临时缓存位置。
当然,在 unix 类型的系统上,我们可以只使用 filename:join(["/tmp", Prefix, Rand]),但 /tmp 在 Windows 上不可用是重点。
【讨论】:
ensure_dir(Name) 在filelib 模块中。链接 - erlang.org/doc/man/filelib.html#ensure_dir-1
你也可以使用TMP = lib:nonl(os:cmd("mktemp")).
【讨论】:
string:strip(os:cmd("mktemp"), right, $\n) 可以避免通常会在最后返回的烦人的隐形换行符。
lib:nonl( os:cmd( "mktemp" ) ).
lib:nonl/1 在OTP 21 中被删除,替换的似乎是string:chomp/1。
或者你可以这样做
erlang:phash2(make_ref())
用于快速简便的唯一标识符。最多可用于 2^82 次调用,这对于您的目的来说应该足够了。我发现这比使用节点名称格式化时间戳更容易。
【讨论】:
您的意思是只生成实际文件名吗?在这种情况下,最安全的方法是混合使用您从 now() 获得的数字和计算机的主机名(如果您有多个节点在做同样的事情)。
类似:
1> {A,B,C}=now().
{1249,304278,322000}
2> N=node().
nonode@nohost
3> lists:flatten(io_lib:format("~p-~p.~p.~p",[N,A,B,C])).
"nonode@nohost-1249.304278.322000"
4>
【讨论】:
erlang:now/0 已弃用,请改用erlang:unique_integer/0 (docs)。
迟到的答案:我刚刚注意到 test_server 模块支持暂存目录,值得一看
【讨论】:
stdlib.h 中有mkstemp。来自 GNU coreutils 的 mktemp 在内部使用 mkstemp 调用。
在 OTP 24 中没有 file:ensure_dir。所以我做了类似的东西:
对于目录:
mktemp_dir(Prefix) ->
Rand = integer_to_list(binary:decode_unsigned(crypto:strong_rand_bytes(8)), 36),
TempDir = filename:basedir(user_cache, Prefix),
[]= os:cmd("mkdir " ++ "\"" ++ TempDir ++ "\""),
{ok, _} = file:list_dir(TempDir),
TempDir.
对于文件:
mktemp(Prefix) ->
Rand = integer_to_list(binary:decode_unsigned(crypto:strong_rand_bytes(8)), 36),
TempDir = filename:basedir(user_cache, Prefix),
TempFile = filename:join(TempDir, Rand),
[]= os:cmd("mkdir " ++ "\"" ++ TempDir ++ "\""),
{ok, _} = file:list_dir(TempDir),
Result = file:write_file(TempFile, <<>>),
case {Result} of
{ok} -> {ok, TempFile};
{Error} -> Error
end.
【讨论】: