问题 如何在没有外部工具的命令提示符下创建唯一的临时文件路径? [重复]


这个问题在这里已有答案:


3080
2017-08-20 01:08


起源



答案:


尝试下一个代码段:

@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 . . .

7
2017-08-20 03:41



问题是,%RANDOM%是从当前时间(以秒为单位)生成的函数,这意味着当您需要第二个文件时,您的代码将循环1秒。 - Sergei
@Sergei不。正在运行 echo %time%&>NUL (for /l %G in (1,1,120) do @call d:\bat\SO\32107998.bat)&cmd /V /C "echo !time!"&dir D:\test\afolderpath\withoutspaces|find "File(s)" 表明 所有  720 文件(= 6 * 120)是在cca 3.5秒内重复创建的(现在我在每个测试目录中都有给定模板模式的cca 1220文件)。读 ss64.com/nt/syntax-random.html - JosefZ
当我快速运行相同的命令时,我得到了这个 imgur.com/a/6SVmu - Sergei
@Sergei抱歉,我无法重现您的结果。请提出一个新问题,提供完整的背景信息 最小,完整和可验证的例子。 - JosefZ
@JosefZ,可悲的是,我无法保证这一切都会有效。如果在一个足够紧密的循环中调用,那么这将产生一些尚未创建的重复项。当你接到很多电话,并且磁盘访问速度慢时,机会就会增加。确保它的好处的唯一方法是在机制中包含一个锁文件。这不是一个糟糕的第一次开始,但没有替代unix mktemp。 - UKMonkey


答案:


尝试下一个代码段:

@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 . . .

7
2017-08-20 03:41



问题是,%RANDOM%是从当前时间(以秒为单位)生成的函数,这意味着当您需要第二个文件时,您的代码将循环1秒。 - Sergei
@Sergei不。正在运行 echo %time%&>NUL (for /l %G in (1,1,120) do @call d:\bat\SO\32107998.bat)&cmd /V /C "echo !time!"&dir D:\test\afolderpath\withoutspaces|find "File(s)" 表明 所有  720 文件(= 6 * 120)是在cca 3.5秒内重复创建的(现在我在每个测试目录中都有给定模板模式的cca 1220文件)。读 ss64.com/nt/syntax-random.html - JosefZ
当我快速运行相同的命令时,我得到了这个 imgur.com/a/6SVmu - Sergei
@Sergei抱歉,我无法重现您的结果。请提出一个新问题,提供完整的背景信息 最小,完整和可验证的例子。 - JosefZ
@JosefZ,可悲的是,我无法保证这一切都会有效。如果在一个足够紧密的循环中调用,那么这将产生一些尚未创建的重复项。当你接到很多电话,并且磁盘访问速度慢时,机会就会增加。确保它的好处的唯一方法是在机制中包含一个锁文件。这不是一个糟糕的第一次开始,但没有替代unix mktemp。 - UKMonkey


首先,使用单独的文件夹将大大降低其他程序入侵的机会。因此,我们将临时文件存储在一个非常长且特定的私人文件夹中,以防止任何名称竞争。

生成名称时,您可以随时使用 %random% 并尝试生成一个不存在的名称,但是使用此操作的次数越多,它变得越无效。如果您计划使用此过程10次,因为随机函数限制为32000(大约),您的程序将花费永远产生随机尝试。

下一个最好的方法是在一个计数器上启动计数器并增加它,直到你有一个未使用的名称。这样你可以保证你的程序最终会在合理的时间内找到一个名字,但是你的文件会堆积起来(这绝不是一个好的经历)

一些人所做的事情(我建议你的情况)是将这些与流程相结合,以便在选择名称时有效减少脂肪,同时使用可靠的方法(两全其美):

@echo off

:: Set Temp Folder Path
set "tp=%temp%\Temporary Name Selection Test"

:: File name will be XXXXXX_YY.txt 
:::: X's are randomly generated
:::: Y's 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

1
2017-08-20 06:09





我建议你使用两种方法之一。 “技术方法”是使用JScript的 FileSystemObject.GetTempName 方法。 JScript是一种预装在XP上所有Windows版本中的编程语言,它通过“Batch-JScript”混合脚本在Batch中使用非常简单:

@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%

1
2017-08-20 10:04