繁体   English   中英

ForFiles 使用时间戳批量移动和重命名文件

[英]ForFiles to batch move & rename file(s) with timestamp

我有一堆每小时/每天创建的 *.mp4 和 *.jpg 文件,它们使用以下文件结构:

-- before:
c:\video\2017-10-15\21hour\jpg\12.13.15[M][0@0][0].jpg
c:\video\2017-10-15\21hour\mp4\12.13.01-12.14.32[M][0@0][0].mp4
c:\video\2017-10-18\16hour\jpg\21.42.31[M][0@0][0].jpg
c:\video\2017-10-18\16hour\mp4\21.42.31-21.45.38[M][0@0][0].mp4

我希望所有 *.jpg 和 *.mp4 文件都移动到 c:\\video\\ 并且完全放弃“date_time”+ 扩展名的旧名称,类似于以下内容:

-- after:
c:\video\2017-10-15_12.13.15.jpg
c:\video\2017-10-15_12.13.01-12.14.32.mp4
c:\video\2017-10-18_21.42.31.jpg
c:\video\2017-10-18_21.42.31-21.45.38.mp4

我发现了 ForFiles,并且能够使用 /s 递归搜索所有子文件夹并将 *.mp4 和 *.jpg 移动到一个位置:

forfiles /p c:\video\ /s /m *.mp4 /c "cmd /c move @PATH c:\video\"
forfiles /p c:\video\ /s /m *.jpg /c "cmd /c move @PATH c:\video\"

现在进行重命名,此时我几乎可以尝到胜利的滋味,因为这为我提供了所需的文件名输出:

forfiles /p c:\video\ /s /m *.mp4 /c "cmd /c echo @FDATE_@FTIME.mp4"
forfiles /p c:\video\ /s /m *.jpg /c "cmd /c echo @FDATE_@FTIME.jpg"

但是,当我用 ren/rename/move 替换 echo 时,出现错误:系统找不到指定的路径。 命令的语法不正确。

但是错误仅在我使用@FDATE 和/或@FTIME 时发生。 这些变量都可以正常工作:@FNAME、@ISDIR、@FSIZE

forfiles /p c:\video\ /m *.mp4 /c "cmd /c ren @FILE @ISDIR.@EXT"
forfiles /p c:\video\ /m *.mp4 /c "cmd /c rename @FILE @FSIZE.@EXT"
forfiles /p c:\video\ /m *.mp4 /c "cmd /c move @FILE @EXT.@EXT"

一旦我让重命名部分工作,我会将移动和重命名合并为一个命令......但我不明白为什么@FDATE & @FTIME 不会,我的语法有问题,或者这只是 ForFiles 不允许的吗?

问题说明

首先,仅用moveren替换echo是行不通的,因为它只会检测传递给它的一个参数。 这可以解释语法错误。

Microsoft Docsren语法

ren [<Drive>:][<Path>]<FileName1> <FileName2> rename [<Drive>:][<Path>]<FileName1> <FileName2>

来自Microsoft Docsmove语法

move [{/y | /-y}] [<Source>] [<Target>]

其次,变量@FDATE@FTIME依赖于语言环境。 它们的格式将取决于您设备的区域格式,例如@FDATE的格式可以包含/@FTIME的格式包含: 这些是保留字符,如果误用可能会导致错误。 这可以解释路径错误。


使用forfiles的解决方案

如果要使用forfiles执行此操作,则必须使用for命令,如下所示 您可以通过提取子字符串来更改日期格式,就像在这个答案中一样 您可以通过将冒号:替换为点来更改时间格式. 在这里解释。

您可以对 .jpg 使用/m一次,对 .mp4 再次使用/m ,但您也可以像这样尝试for loop 这意味着您必须将示例中的for嵌套在另一个for循环中。

move /? , 如果您只移动一个文件,您也可以重命名它。

示例:

setlocal EnableDelayedExpansion

for %%F in (.jpg, .mp4) do (
    for /f "tokens=1,2,3,4 delims=|" %%A in (
        'forfiles /p "C:\video" /s /m "*%%F" /c "cmd /c echo @PATH^|@EXT^|@FDATE^|@FTIME"'
        ) do (
        set filepath=%%~A
        set extension=%%~B
        set datestamp=%%~C
        set timestamp=%%~D
        set parseddate=!datestamp:~6,4!-!datestamp:~3,2!-!datestamp:~0,2!
        move "!filepath!" "C:\video\!parseddate!_!timestamp::=.!.!extension!"
    )
)

endlocal

如果文件数很大,批处理需要一点时间才能完成。 forfiles必须首先读取文件, for循环也必须遍历该文件列表。 此外, forfiles依赖于语言环境。 如果您设备的区域日期格式是2020/02/10那么我的示例2020/02/10字符串的索引不正确。


使用 PowerShell 的解决方案

.NET Framework 的LastWriteTime属性与区域设置无关,因为它不依赖于您设备的区域格式。 如果您更喜欢使用 UTC,还有一个LastWriteTimeUtc属性。 不过,您仍然必须在批处理文件中使用for循环。

PowerShell 的Get-ChildItem返回由-Path参数指定的父文件夹的所有子文件夹,您可以使用-Recurse参数递归执行此操作。 如果您希望结果只包含 .jpg 和 .mp4 文件,您应该使用-Include *.jpg, *.mp4 通常在使用-Include您需要将\\*附加到路径,但由于使用了-Recurse ,因此没有必要。

随着Get-ItemProperty-Name参数,您可以列出FullnameLastWriteTimeExtension性。 为了使for循环更具可读性,它们必须像$var.Property一样被调用并连接起来。 ToString()必须用于将LastWriteTime转换为字符串并更改其格式。

示例:

for /f "tokens=1,2 usebackq delims=|" %%A in (
    `powershell -Command "& {Get-ChildItem -Path 'C:\video\*' -Recurse -Include *.jpg, *.mp4 | ForEach {Get-ItemProperty -Path $_.FullName -Name FullName, LastWriteTime, Extension} | ForEach {$_.FullName+'|'+$_.LastWriteTime.ToString('yyyy-MM-dd_HH.mm.ss')+$_.Extension}}"`
) do (
    move "%%~A" "C:\video\%%~B"
)

注意:您可以省略-Path ,但第一个参数必须是路径。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM