如何在命令提示符中创建唯一的临时文件路径,而无需外部工具



我正在尝试创建要在批处理文件中使用的临时文件的路径。

环境变量%TEMP%%TMP%用于获取当前用户的临时目录。但是如何构建一个肯定还不存在的文件名呢?

当然,我可以使用内置变量%RANDOM%并创建类似bat~%RANDOM%.tmp的东西,但是该方法不能确保文件当前不存在(或者在我第一次在磁盘上创建它并写入它之前,它将碰巧由另一个应用程序创建)—尽管这一切都是非常不可能的。

我知道我可以通过附加%DATE%/%TIME%来减少这种碰撞的概率,或者通过添加多个%RANDOM%实例,但这不是我想要的…

注意:根据这篇文章,在。net (Path.GetTempFileName())中有一种方法完全符合我的要求(除了明显错误的编程语言)。

尝试下一个代码片段:

@echo off
setlocal EnableExtensions
rem get unique file name 
:uniqLoop
set "uniqueFileName=%tmp%bat~%RANDOM%.tmp"
if exist "%uniqueFileName%" goto :uniqLoop

或create procedures

  • :uniqGet:创建一个修复文件名模板的文件(在您的例子中是bat~%RANDOM%.tmp);
  • :uniqGetByMask:创建一个变量文件名模板的文件。注意在过程调用prefix%%%%random%%%%suffix.ext%random%引用的百分比符号翻了四倍。还要注意高级用法:CALLcall set "_uniqueFileName=%~2"过程中的内部命令。

代码可以如下所示:

@ECHO OFF
SETLOCAL enableextensions
call :uniqGet uniqueFile1 "%temp%"
call :uniqGet uniqueFile2 "%tmp%"
call :uniqGet uniqueFile3 d:testafolderpathwithoutspaces
call :uniqGet uniqueFile4 "d:testa folder pathwith spaces"
call :uniqGetByMask uniqueFile7 d:testafolderwithoutspacesprfx%%%%random%%%%sffx.ext
call :uniqGetByMask uniqueFile8 "d:testa folderwith spacesprfx%%%%random%%%%sffx.ext"
set uniqueFile
pause
goto :continuescript
rem get unique file name procedure
rem usage: call :uniqGetByMask VariableName "folderpathprefix%%%%random%%%%suffix.ext"
rem parameter #1=variable name where the filename save to
rem parameter #2=folderfile 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=%~2bat~%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:batSO32107998.bat
uniqueFile1=D:tempUsermebat~21536.tmp
uniqueFile2=D:tempUsermebat~15316.tmp
uniqueFile3=d:testafolderpathwithoutspacesbat~12769.tmp
uniqueFile4=d:testa folder pathwith spacesbat~14000.tmp
uniqueFile7=d:testafolderwithoutspacesprfx26641sffx.ext
uniqueFile8=d:testa folderwith spacesprfx30321sffx.ext
Press any key to continue . . .

我建议您以下两种方法之一。"技术方法"是使用JScript的FileSystemObject。GetTempName方法。JScript是一种编程语言,从XP开始预装在所有Windows版本中,通过"批处理-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%

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

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

下一个最好的方法是在1处开始计数器,然后增加计数器,直到有一个未使用的名称。这样你就可以保证你的程序最终会在合理的时间内找到一个名字,但是你的文件又会堆积起来(这绝对不是一个好的体验)

有些人所做的(我建议针对你的情况)是将这些过程结合起来,在使用可靠的方法(两全其美)的同时,有效地减少选择名称的赘肉:

@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

最新更新