I need to put data in a file since my other function takes a file as input.
How do I create a unique filename in Erlang?
Does something like unix "tempfile" exist?
I've finally had this problem -- and my user is using a mix of Windows and Linux systems, so the old tried-and-true lib:nonl(os:cmd("mktemp"))
method is just not going to cut it anymore.
So here is how I've approached it, both with a mktemp/1
function that returns a filename that can be used and also a mktemp_dir/1
function that returns a directory (after having created it).
-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.
And the directory version:
-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.
Both of these do basically the same thing: we get a strongly random name as a binary, convert that to a base36 string, and append it to whatever the OS returns to us as a safe user-local temporary cache location.
On a unix type system, of course, we could just use filename:join(["/tmp", Prefix, Rand])
but the unavailability of /tmp
on Windows is sort of the whole point here.
You can also use TMP = lib:nonl(os:cmd("mktemp")).
Do you mean just generate the acutal filename? In that case the safest way would be to use a mix of the numbers you get from now() and the hostname of your computer (if you have several nodes doing the same thing).
Something like:
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])).
"[email protected]"
4>
Or you could do
erlang:phash2(make_ref())
for a quick and easy unique indentifier. Unique for up to 2^82 calls which should be enough.for your purposes. I find this easier than formatting a timestamp with node name for use.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With