使用Windows脚本无法多次复制文件

时间:2016-03-04 05:31:00

标签: windows batch-file

我正在尝试使用Windows批处理脚本将文件从一个目录复制到另一个目录,并为其附加时间戳。目标目录为空时,它只能运行一次。如果我再次运行批处理脚本,则表示在指定目录中找不到文件。奇怪的是,当我将原始文件名与时间戳连接起来时,下次它会在源目录中查找带有连接字符串的文件名。请帮忙。

    @echo off

for /f "delims=" %%a in ('wmic OS Get localdatetime  ^| find "."') do set dt=%%a
set YYYY=%dt:~0,4%
set MM=%dt:~4,2%
set DD=%dt:~6,2%
set HH=%dt:~8,2%
set Min=%dt:~10,2%
set Sec=%dt:~12,2%

set stamp=%YYYY%-%MM%-%DD%_%HH%-%Min%-%Sec%

SET "destpath=C:\RatePDF\backup\"
SET "sourcepath=C:\RatePDF\"

for /r "%sourcepath%" %%f in (*.xlsx) do (

    SET name=%%~nf
)

echo %name%

SET newFileName = %name%-%stamp%

COPY "%sourcepath%\%name%.xlsx" "%destpath%\%newFileName%.xlsx"

pause

2 个答案:

答案 0 :(得分:1)

使用插入文件名复制文件的时间戳比大多数人想象的要困难。有关详细信息和完整说明,请查看Create a backup copy of files

下面的批处理文件代码适用于将目录C:\RatePDF中的* .xlsx文件复制到文件名中的当前日期和时间到子目录backup的任务。

@echo off
rem Note: Remove both /V for copying large files faster without verification.

setlocal EnableDelayedExpansion
set "SourcePath=C:\RatePDF"
if not exist "%SourcePath%\*.xlsx" exit /B
set "DestPath=%SourcePath%\backup"

rem Get local date and time in region and language independent format YYYYMMDDHHmmss.
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS get LocalDateTime /format:value') do set "LocalDateTime=%%I"

rem Reformat the local date and time to format YYYY-MM-DD_HH-mm-ss.
set "LocalDateTime=%LocalDateTime:~0,4%-%LocalDateTime:~4,2%-%LocalDateTime:~6,2%_%LocalDateTime:~8,2%-%LocalDateTime:~10,2%-%LocalDateTime:~12,2%"

rem Command COPY can't be used for copying files with either hidden or
rem system attribute set or if destination file exists already and has
rem read-only attribute set. Therefore must use the command XCOPY as this
rem command can copy also hidden and system files by using option /H,
rem with keeping the attributes of copied file by using option /K,
rem with overwriting also already existing file by using option /Y,
rem even if destination file is read-only by using option /R,
rem with verifying also successful copying of file by using option /V
rem and with automatic continuation on failure by using option /C.

rem But there is a real problem on using XCOPY for copying a single file:
rem It prompts the user if the destination is a file or a directory if the
rem destination file does not already exist. And this prompt depends on
rem language of operating system.

rem A hack is used to get the language dependent letter from prompt text
rem without really copying any file. Command XCOPY is used to start copying
rem the batch file itself to folder for temporary files with file extension
rem being TMP for destination file. This results in a prompt by XCOPY if
rem there is not already a file with that name in temporary files folder
rem which is very unlikely. The handler of device NULL is used as an input
rem handler for XCOPY resulting in breaking the copying process after the
rem prompt was output by XCOPY 2 times. This output is processed in a FOR
rem loop which is exited on first line starting with an opening parenthesis.
rem This is the line on which second character defines the letter to use
rem for specifying that destination is a file.

del /F "%TEMP%\%~n0.tmp" 2>nul
for /F %%I in ('%SystemRoot%\System32\xcopy.exe "%~f0" "%TEMP%\%~n0.tmp" ^<nul') do (
    set "PromptAnswer=%%I"
    if "!PromptAnswer:~0,1!" == "(" (
        set "PromptAnswer=!PromptAnswer:~1,1!"
        goto CreateBackups
    )
)
echo ERROR: Failed to determine letter for answering prompt of XCOPY.
exit /B

:CreateBackups
if not exist "%DestPath%\" md "%DestPath%"
rem Note: Files with hidden attribute set are ignored by this FOR loop.
for %%F in ("%SourcePath%\*.xlsx") do call :CopyFile "%%~F"
exit /B

rem Subroutine for copying a single file which always has a file
rem extension because this batch file is for copying *.xlsx files.

:CopyFile
set "FileName=%~n1"
set "FileExtension=%~x1"

echo Copy "%~f1" to "%DestPath%\%FileName%_%LocalDateTime%%FileExtension%"

rem Try to copy the file with standard command COPY with verification.
copy /V /Y "%~f1" "%DestPath%\%FileName%_%LocalDateTime%%FileExtension%" >nul 2>&1

rem Copying failed if exit code of COPY is greater or equal 1.
if errorlevel 1 goto UseXcopy
echo Success
exit /B

rem Another issue to solve is that XCOPY is not reliable on error codes.
rem For example if option /R would not be used and destination file has
rem read-only attribute set, the single file copy fails with error message
rem access denied written to STDERR stream, but the exit code of XCOPY is
rem nevertheless 0 like on a successful copy. On other errors the exit code
rem is correct like write access on existing destination file fails because
rem the destination file is opened currently by an application with blocking
rem shared access completely or allows just shared read for the file.

rem So instead of evaluating the exit code, XCOPY is executed within a FOR
rem loop to evaluate the number of copied files output on last line by XCOPY
rem to STDOUT stream. The number of copied files is 1 on successful copy of
rem the single file. Any other string (number 0) is interpreted as failed
rem copy of the specified file. Output of copied files is suppressed by
rem using option /Q of XCOPY.

:UseXcopy
for /F %%I in ('echo %PromptAnswer% ^| %SystemRoot%\System32\xcopy.exe "%~f1" "%DestPath%\%FileName%_%LocalDateTime%%FileExtension%" /C /H /K /Q /R /V /Y') do set "FilesCopied=%%I"
if not "%FilesCopied%" == "1" (
    echo ERROR: Creating the backup failed, see error message above.
    exit /B
)
echo Success
exit /B

注意1:具有隐藏属性集的* .xlsx文件不会与此批处理文件一起复制。

注2:批处理文件包含一些echo打印的行,哪些文件被复制,如果该副本成功或失败。批处理文件按预期工作后,应删除这些行。

您的一个错误是使用/RC:\RatePDF中的所有* .xlsx文件递归复制到C:\RatePDF\backup,因为目标备份目录是源目录的子目录。因此,您的批处理文件将创建副本副本的副本...有问题,不是吗。

要了解使用的命令及其工作原理,请打开命令提示符窗口,执行以下命令,并完全阅读为每个命令显示的所有帮助页面。

  • call /?
  • copy /?
  • del /?
  • echo /?
  • exit /?
  • for /?
  • goto /?
  • if /?
  • md /?
  • rem /?
  • set /?
  • setlocal /?
  • wmic OS get /?

另请阅读Microsoft文章Using command redirection operatorsTesting for a Specific Error Level in Batch Files

答案 1 :(得分:0)

我看到两个问题。

首先,您的for /r会将name设置为在sourcedir创建的目录树中找到的最后一个文件名。

由于您的目标目录位于源树中,因此找到的名称可能是您在上一次运行中创建的文件的名称。

因此,第一次运行将sourcepath=C:\RatePDF\file.txt复制到C:\RatePDF\backup\file.txt-2016-03-03-18-36(或类似的东西)

一切都很好,但在第二次运行时,检测到的最后一个文件名将是file.txt-2016-03-03-18-36 - 但这是C:\RatePDF\backup而不是``C:\ RatePDF hence the文件丢失了报告。

解决方案:丢失/r

下一个问题:

SET newFileName = %name%-%stamp%

将变量newFileName space 设置为 space %name% - %stamp%

因此行

COPY "%sourcepath%\%name%.xlsx" "%destpath%\%newFileName%.xlsx"

nothing 替换为newfilename的目标文件名,因为它未定义。

解决方案:丢失set命令中的两个杂散空格。