У меня наконец-то возникла эта проблема - и мой пользователь использует сочетание систем 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 = file: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 = file: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 - вот в чем вся суть.