Question

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?

Was it helpful?

Solution

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])).
"nonode@nohost-1249.304278.322000"
4> 

OTHER TIPS

You can also use TMP = lib:nonl(os:cmd("mktemp")).

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.

Late answer: I just noticed the test_server module which has scratch directory support, worth a look

http://www.erlang.org/doc/man/test_server.html#temp_name-1

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 = file: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 = file: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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top