Как создать уникальный временный путь к файлу в командной строке без внешних инструментов?
Я пытаюсь создать путь к временному файлу, который будет использоваться в пакетном файле.
Существуют переменные окружения %TEMP%
и %TMP%
, чтобы получить временный каталог для текущего пользователя. Но как создать имя файла, которое, безусловно, еще не существует?
Конечно, я могу использовать встроенную переменную %RANDOM%
и создать что-то вроде bat~%RANDOM%.tmp
, но этот метод не гарантирует, что файл в настоящее время не существует (или что он будет создан по совпадению другим приложением, прежде чем я сначала создайте его на диске и напишите ему) - хотя это все очень маловероятно.
Я знаю, что могу просто уменьшить вероятность таких столкновений, добавив также %DATE%
/%TIME%
, или просто добавив несколько экземпляров %RANDOM%
, но это не то, что я хочу...
Примечание: В соответствии с этим сообщением существует метод .NET(Path.GetTempFileName()
), который делает именно то, что я прошу для (помимо, конечно, неправильного языка программирования).
Ответы
Ответ 1
Попробуйте следующий фрагмент кода:
@echo off
setlocal EnableExtensions
rem get unique file name
:uniqLoop
set "uniqueFileName=%tmp%\bat~%RANDOM%.tmp"
if exist "%uniqueFileName%" goto :uniqLoop
или создать процедуры
-
:uniqGet
: создайте файл шаблона имени файла исправления (bat~%RANDOM%.tmp
в вашем случае);
-
:uniqGetByMask
: создать файл с переменным именем файла. Обратите внимание на четырехкратные процентные знаки ссылки %random%
в вызове процедуры: prefix%%%%random%%%%suffix.ext
. Также обратите внимание на расширенное использование: CALL
внутренние команды в call set "_uniqueFileName=%~2"
внутри процедуры.
Код может быть следующим:
@ECHO OFF
SETLOCAL enableextensions
call :uniqGet uniqueFile1 "%temp%"
call :uniqGet uniqueFile2 "%tmp%"
call :uniqGet uniqueFile3 d:\test\afolderpath\withoutspaces
call :uniqGet uniqueFile4 "d:\test\a folder path\with spaces"
call :uniqGetByMask uniqueFile7 d:\test\afolder\withoutspaces\prfx%%%%random%%%%sffx.ext
call :uniqGetByMask uniqueFile8 "d:\test\a folder\with spaces\prfx%%%%random%%%%sffx.ext"
set uniqueFile
pause
goto :continuescript
rem get unique file name procedure
rem usage: call :uniqGetByMask VariableName "folderpath\prefix%%%%random%%%%suffix.ext"
rem parameter #1=variable name where the filename save to
rem parameter #2=folder\file mask
:uniqGetByMask
rem in the next line (optional): create the "%~dp2" folder if does not exist
md "%~dp2" 2>NUL
call set "_uniqueFileName=%~2"
if exist "%_uniqueFileName%" goto :uniqGetByMask
set "%~1=%_uniqueFileName%"
rem want to create an empty file? remove the `@rem` word from next line
@rem type nul > "%_uniqueFileName%"
exit /B
goto :continuescript
@rem get unique file name procedure
@rem usage: call :uniqGet VariableName folder
@rem parameter #1=variable name where the filename save to
@rem parameter #2=folder where the file should be about
:uniqGet
@rem in the next line (optional): create the "%~2" folder if does not exist
md "%~2" 2>NUL
set "_uniqueFileName=%~2\bat~%RANDOM%.tmp"
if exist "%_uniqueFileName%" goto :uniqGet
set "%~1=%_uniqueFileName%"
@rem want to create empty file? remove the `@rem` word from next line
@rem type nul > "%_uniqueFileName%"
exit /B
:continueScript
Выход
==>D:\bat\SO\32107998.bat
uniqueFile1=D:\tempUser\me\bat~21536.tmp
uniqueFile2=D:\tempUser\me\bat~15316.tmp
uniqueFile3=d:\test\afolderpath\withoutspaces\bat~12769.tmp
uniqueFile4=d:\test\a folder path\with spaces\bat~14000.tmp
uniqueFile7=d:\test\afolder\withoutspaces\prfx26641sffx.ext
uniqueFile8=d:\test\a folder\with spaces\prfx30321sffx.ext
Press any key to continue . . .
Ответ 2
Во-первых, использование отдельной папки значительно снизит вероятность вторжения других программ. Поэтому давайте храним временный файл в частной папке, которая действительно длинна и специфична для предотвращения конкуренции имен.
При создании имени вы всегда можете использовать %random%
и попробуйте создать имя, которое не существует, однако чем больше раз эта операция используется, тем более неэффективным становится. Если вы планируете использовать этот процесс в 10 тысяч раз, поскольку случайная функция ограничена 32000 (приблизительно), ваша программа будет тратить навсегда произвольные попытки.
Следующий лучший подход - запустить счетчик на одном и увеличить его до тех пор, пока у вас не будет неиспользуемого имени. Таким образом, вы можете гарантировать, что ваша программа в конечном итоге найдет имя в разумные сроки, однако ваши файлы будут накапливаться (что никогда не бывает хорошим опытом).
То, что некоторые люди делают (и я бы рекомендовал для вашей ситуации), сочетают их с процессами, чтобы эффективно вырезать жир при выборе имени, используя надежный метод (лучший из обоих миров):
@echo off
:: Set Temp Folder Path
set "tp=%temp%\Temporary Name Selection Test"
:: File name will be XXXXXX_YY.txt
:::: X are randomly generated
:::: Y are the incremented response to existing files
set x=%random%
set y=0
set "filename=Unexpected Error"
:loop
set /a y+=1
set "filename=%tp%\%x%_%y%.txt"
if exist %filename% goto loop
:: At this point, filename is all good
Echo %filename%
pause
Ответ 3
Я предлагаю вам один из двух методов. "Технический подход" заключается в использовании JScript метода FileSystemObject.GetTempName. JScript - это язык программирования, который предварительно устанавливается во всех версиях Windows из XP, а его использование в Batch с помощью гибридного script "Batch-JScript" очень просто:
@if (@CodeSection == @Batch) @then
@echo off
setlocal
for /F "delims=" %%a in ('CScript //nologo //E:JScript "%~F0"') do set "tempName=%%a"
echo Temp name: "%tempName%"
goto :EOF
@end
// JScript section
var fso = new ActiveXObject("Scripting.FileSystemObject");
WScript.Stdout.WriteLine(fso.GetTempName());
Однако самый простой способ - сохранить номер в файле данных и каждый раз, когда вы хотите получить новое имя, получить номер, увеличить его и сохранить его обратно в том же файле. Это будет работать "просто" 2147483647 раз!
rem Get next number
set /P "nextNum=" < NextNumber.txt
set /A nextNum+=1
echo %nextNum% > NextNumber.txt
set "tempName=File%nextNum%.txt"
echo Temp name: %tempName%