Любая система, которая опирается на случайное число теоретически может потерпеть неудачу, даже с помощью одного GUID. Но мир, похоже, согласился с тем, что GUID достаточно хороши. Я где-то видел код, который использует CSCRIPT JScript для генерации GUID.
Есть и другие способы:
Сначала я буду считать, что вы пытаетесь создать уникальный временный файл. Поскольку файл будет удален после завершения процесса, все, что вам нужно сделать, это установить исключительную блокировку ресурса, чье имя является производным от вашего имени файла temp. (на самом деле я иду наоборот - имя temp происходит от имени заблокированного ресурса).
Redirection устанавливает исключительную блокировку выходного файла, поэтому я просто получаю имя от времени (с 0.01 секундой preciscion) и пытаюсь заблокировать файл с этим именем в временной папке пользователя. Если это не удастся, я вернусь назад и повторю попытку, пока не добьюсь успеха. Как только у меня будет успех, я гарантированно получаю право собственности на этот замок и все производные (если кто-то не намеренно нарушает систему).
Как только мой процесс завершится, блокировка будет выпущена, и временный файл с тем же именем может быть повторно использован позже.Но сценарий обычно удаляет временный файл после завершения.
@echo off
setlocal
:getTemp
set "lockFile=%temp%\%~nx0_%time::=.%.lock"
set "tempFile=%lockFile%.temp"
9>&2 2>nul (2>&9 8>"%lockFile%" call :start %*) || goto :getTemp
:: Cleanup
2>nul del "%lockFile%" "%tempFile%"
exit /b
:start
:: Your code that needs the temp file goes here. This routine is called with the
:: original parameters that were passed to the script. I'll simply write some
:: data to the temp file and then TYPE the result.
>"%tempFile%" echo The unique tempfile for this process is "%tempfile%"
>>"%tempFile%" echo(%*
type "%tempFile%"
exit /b
Цитирование из-за столкновения имен должно быть редким, если вы действительно не подчеркиваете свою систему. Если это так, вы можете уменьшить вероятность зацикливания в 10 раз, если используете WMIC OS GET LOCALDATETIME
вместо %TIME%
.
Если вы ищете постоянного уникального имени, то проблема немного сложнее, так как вы не можете поддерживать блокировку на неопределенный срок. В этом случае я рекомендую использовать метод LocalDateTime для WMIC, в сочетании с двумя проверками на столкновение имен.
Первая проверка просто проверяет, что файл еще не существует. Но это условие гонки - два процесса могут сделать проверку в одно и то же время. Вторая проверка создает файл (пустой) и устанавливает на нем временную исключительную блокировку. Хитрость заключается в том, чтобы убедиться, что блокировка поддерживается в течение определенного периода времени, который больше, чем другой процесс, чтобы проверить, существует ли файл. Я ленив, поэтому я просто использую TIMEOUT, чтобы установить 1 секунду ожидания - это больше, чем нужно.
Процедура getUniqueFile ожидает три аргумента - базовое имя, расширение и имя переменной, в которой должен храниться результат. Базовое имя может содержать информацию о диске и пути. Любая информация о пути должна быть действительной, иначе программа будет вводить бесконечный цикл. Эта проблема может быть исправлена.
@echo off
setlocal
:: Example usage
call :getUniqueFile "d:\test\myFile" ".txt" myFile
echo myFile="%myFile%"
exit /b
:getUniqueFile baseName extension rtnVar
setlocal
:getUniqueFileLoop
for /f "skip=1" %%A in ('wmic os get localDateTime') do for %%B in (%%A) do set "rtn=%~1_%%B%~2"
if exist "%rtn%" (
goto :getUniqueFileLoop
) else (
2>nul >nul (9>"%rtn%" timeout /nobreak 1) || goto :getUniqueFileLoop
)
endlocal & set "%~3=%rtn%"
exit /b
Приведенное выше должно быть гарантировано для возврата нового уникального имени файла для данного пути. Существует много возможностей для оптимизации, чтобы установить некоторую команду для выполнения во время проверки блокировки, которая занимает достаточно много времени, но не слишком длинна.
Не так часто возникает вопрос в [тег: batch-file] land, который требует более 5 ответов. +1 интересный вопрос! – rojo