【问题标题】:How to rename a file while it is being copied and copy complete如何在复制和复制完成时重命名文件
【发布时间】:2016-11-30 02:47:46
【问题描述】:

我想创建一个脚本,它将文件从一个文件夹复制到另一个文件夹。

由于文件可能很大,最高可达 1000 MB,因此可能需要几秒钟的时间 或一分钟完全复制它。发生这种情况时,我希望目标文件夹中的文件名带有下划线(_)前缀。

文件完全复制到目标文件夹后,应从文件名中删除_。这样做的目的是确保另一个进程不应该从目标文件夹中提取不完整的文件。

我们如何使用批处理脚本来做到这一点?目前我的批处理文件正在复制并将文件移动到另一个文件夹,但我不知道如何在文件完全移动后添加下划线前缀,然后再次从文件名中删除。

这是我复制和移动文件的两行代码。

copy %1\Customer_*.xml C:\Users\ard\Documents\Folder1
move %1\Customer_*.xml %1\Archive

如果这不能使用批处理脚本完成,那么 VB 脚本也应该可以工作

【问题讨论】:

    标签: batch-file vbscript


    【解决方案1】:

    删除前缀并非易事,但删除后缀(新扩展名)很简单。所以我会附加一个新的扩展,比如.inProgress。然后,您可以使用通配符使用两个简单的命令来复制和重命名文件集合。

    但是 MOVE 命令不允许重命名多个文件,因此需要一个 FOR 循环。我将展示代码,但我认为在 OP 的场景中这并不是真正必要的。在我看来,源文件夹和目标文件夹位于同一个驱动器上,因此移动应该几乎是即时的,并且不需要使用临时中间名。

    copy "%1\Customer_*.xml" "C:\Users\ard\Documents\Folder1\*.*.inProgress"
    ren "C:\Users\ard\Documents\Folder1\*.inProgress" *.
    
    for %%F in ("%1\Customer_*.xml") do (
      move "%%F" "%1\Archive\%%~nxF.inProgress"
      ren "%1\Archive\%%~nxF.inProgress" *.
    )
    

    请参阅How does the Windows RENAME command interpret wildcards?,了解重命名的原因。

    请注意,在整个 COPY 操作完成之前,所有复制的文件都将显示为“.inProgress”。如果您希望每个文件尽快可用,那么 COPY 也需要一个 FOR 循环:

    for %%F in ("%1\Customer_*.xml") do (
      copy "%%F" "C:\Users\ard\Documents\Folder1\%%~nxF.inProgress"
      ren "C:\Users\ard\Documents\Folder1\%%~nxF.inProgress" *.
    )
    

    【讨论】:

    • 不错的解决方案,我喜欢它。
    • @Tomalak - 除了我有一个错误! MOVE 不允许您使用通配符重命名多个文件。我已经编辑了我的答案。
    • 啊,细节。 ;) 不过,我的评论仍然适用。
    【解决方案2】:

    我的示例使用新名称从 src 复制到 dest,然后恢复旧名称: bn 是源文件的基本名称。

    for %%a in (src\*.xml) do (
    set bn=%%~nxa
    copy %%a dest\!bn!_
    rename dest\!bn!_ !bn!
    )
    

    【讨论】:

    • set bn=%%~nxa 会更好(它也会消除对enabledelayedexpansion 的依赖)
    • 这仍然需要“setlocal ENABLEDELAYEDEXPANSION”。不需要“bn”变量 - 摆脱它,您不需要延迟扩展
    • 另外,没有错误处理。例如:复制 %%a dest\%%~nxa > nul || (回显失败!%%a & exit /b 1)
    【解决方案3】:

    你想要什么,用文字表达:

    对于C:\source中的每个受影响的文件:

    • 将文件x复制到C:\destination\_x
    • 将文件C:\destination\_x 重命名为C:\destination\x

    在 Windows 批处理代码中,还有一些附加功能:

    @echo off
    setlocal
    
    set "SOURCE=%1"
    set "DESTINATION=C:\Users\ard\Documents\Folder1"
    
    for /f "usebackq delims=" %%x in (`dir /b "%SOURCE%\Customer_*.xml"`) do (
        if exist "%DESTINATION%\%%x" (
          echo %%x - already exists at destination
        ) else (
          echo %%x
          copy "%SOURCE%\%%x" "%DESTINATION%\_%%x" > NUL && rename "%DESTINATION%\_%%x" "%%x"
        )
    )
    

    注意事项:

    • for 循环可以逐行迭代命令的输出
    • 在我们的例子中,该命令是dir /b "%SOURCE%\*.xml",即源文件夹中匹配文件的“裸”列表
    • usebackq 表示命令由反引号分隔,允许在命令本身内使用双引号
    • delims= 将字段分隔符设置为“无”,否则 for 会将每个文件名拆分为标记(如果它包含空格)
    • > NUL 禁止“复制 1 个文件”。来自copy 的成功消息
    • && 表示 rename 仅在 copy 成功时执行

    【讨论】:

    • @joeking 这有点像一个不完整的问题。
    • 好的,如果复制或重命名失败会怎样?如果复制失败,它的排序是好的,但它不会告诉你哪个文件失败了。如果重命名失败,它会将临​​时文件留在那里,并且不会告诉您哪个文件失败了。
    • @joeking 好吧...我想我已经添加了许多花里胡哨的方法。我真的不想在我已经做过的基础上进行批量错误处理,因为它超出了问题的范围。我不希望这成为批处理 101。(实际上:如果您刚刚成功复制的文件重命名失败,则说明出现了严重错误,您手头的问题可能比未完成且没有错误的批处理文件更大)
    • 好点。可能是目标中的重复,但脚本会提前检查,所以这似乎不太可能。
    • 如果两个实例并行运行,可能会发生。可以做到这一点,但以牺牲可读性为代价。
    猜你喜欢
    • 2013-06-13
    • 1970-01-01
    • 2021-01-04
    • 2016-11-01
    • 2018-04-21
    • 1970-01-01
    • 1970-01-01
    • 2020-03-24
    • 1970-01-01
    相关资源
    最近更新 更多