2015-08-20 13 views
10

Sto cercando di creare il percorso di un file temporaneo da utilizzare in un file batch.Come creare un percorso di file temporaneo univoco nel prompt dei comandi senza strumenti esterni?

Ci sono le variabili di ambiente %TEMP% e %TMP% per ottenere la directory temporanea per l'utente corrente. Ma come costruire un nome di file che sicuramente non esiste ancora?

Naturalmente posso usare il qualcosa variabile incorporata %RANDOM% e creare come bat~%RANDOM%.tmp, ma questo metodo non non garantisce che il file è attualmente inesistente (o che sarà creato per coincidenza da un'altra applicazione, prima che io prima creala su disco e scrivici), anche se tutto questo è molto improbabile.

so ho potuto solo ridurre la probabilità di tali collisioni aggiungendo anche %DATE%/%TIME%, o semplicemente aggiungendo più %RANDOM% casi, ma questo non è quello che voglio ...

Nota: Secondo this post, c'è un metodo in .NET (Path.GetTempFileName()) che fa esattamente quello che sto chiedendo (oltre al linguaggio di programmazione sbagliato ovviamente).

risposta

6

Prova codice successivo frammento:

@echo off 
setlocal EnableExtensions 

rem get unique file name 
:uniqLoop 
set "uniqueFileName=%tmp%\bat~%RANDOM%.tmp" 
if exist "%uniqueFileName%" goto :uniqLoop 

o creare procedure

  • :uniqGet: creare un file di un modello di correzione nome del file (bat~%RANDOM%.tmp nel tuo caso);
  • :uniqGetByMask: crea un file di un modello di nomefile di variabile. Nota i segni percentuali quadruplicati del riferimento %random% in una chiamata di procedura: prefix%%%%random%%%%suffix.ext. Nota anche advanced usage: CALLing internal commands in call set "_uniqueFileName=%~2" all'interno della procedura.

Il codice potrebbe essere la seguente:

@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 

uscita:

==>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 . . . 
+0

Il problema è,% RANDOM% viene generato come una funzione dall'ora corrente (in secondi), il che significa che il codice sarà in un ciclo per 1 secondo quando è necessario un secondo file. – Sergei

+0

@Sergei Nope. In esecuzione ad es. 'echo% time% &> NUL (per/l% G in (1,1,120) do @call d: \ bat \ SO \7998.bat) & cmd/V/C" echo! time! "& dir D: \ test \ afolderpath \ withoutspaces | find "File (s)" 'mostra che ** tutti i file **' 720' (= 6 * 120) vengono creati durante cca 3,5 secondi, ripetutamente (ora ho file cca 1220 di un modello di modello dato in ogni directory di test). Leggi https://ss64.com/nt/syntax-random.html – JosefZ

+0

Quando eseguo lo stesso comando molto velocemente ottengo questo http://imgur.com/a/6SVmu – Sergei

1

In primo luogo, utilizzando una cartella separata ridurrà notevolmente le probabilità di altri programmi di intrusione. Quindi, consente di archiviare il file temporaneo in una cartella privata molto lunga e specifica per evitare qualsiasi competizione di nomi.

Quando si genera il nome, è sempre possibile utilizzare e provare a generare un nome che non esiste, tuttavia più volte viene utilizzata questa operazione, più diventa inefficace. Se si prevede di utilizzare questo processo 10 di migliaia di volte poiché la funzione casuale è limitata a 32000 (circa), il programma spenderà per sempre generando tentativi casuali.

Il prossimo approccio migliore è avviare un contatore ad uno e aumentarlo fino ad avere un nome inutilizzato.In questo modo puoi garantire che il tuo programma troverà un nome in un ragionevole lasso di tempo, tuttavia i tuoi file si accumuleranno (che non è mai una buona esperienza)

Cosa fanno alcune persone (e lo consiglierei per la tua situazione) è combinare queste ai processi per ridurre efficacemente il grasso nella scelta di un nome, mentre si utilizza un metodo affidabile (il meglio dei due mondi):

@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

vi consiglio uno dei due metodi. L '"approccio tecnico" è quello di utilizzare il metodo FileSystemObject.GetTempName di JScript. JScript è un linguaggio di programmazione che viene pre-installato in tutte le versioni di Windows da XP in poi, e il suo uso in batch tramite uno script ibrido "Batch-JScript" è molto semplice:

@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()); 

Tuttavia, l'approccio più semplice è quello di memorizzare un numero in un file di dati e ogni volta che si desidera un nuovo nome, ottenere il numero, incrementarlo e memorizzarlo nello stesso file. Questo funzionerà per "solo" 2147483647 volte!

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% 
Problemi correlati