标题: [文件操作] 批处理如何提高效率:复制源文件夹中新近创建的文件至指定文件夹 [打印本页]
作者: alredstone 时间: 2022-5-17 18:03 标题: 批处理如何提高效率:复制源文件夹中新近创建的文件至指定文件夹
本帖最后由 alredstone 于 2022-5-18 12:36 编辑
=============== 以下为最近一次编辑的内容 ===============
目标:遍历每个文件获取其创建日期,并和指定日期进行比对,最后复制或跳过。
结论:继续求教更高执行效率的处理办法。
以下为讨论部分:
关于bat执行效率的问题,论坛里有较多讨论,@随风 版主也做了汇总 http://www.bathome.net/thread-4828-1-1.html 。 然而执行效率问题依旧是绕不过的坎。
在坛友 @idwma 的建议下,我尝试将多次调用 call 和 goto 改为 for 和 if 语句,因此也引入了 管道 和 findstr 。最终测试结果发现,两者对于1000个文件的处理,差异不大(3秒以内,重复三次)。
目前可获得的结论如下:重复调用 call 和 goto 与重复使用 管道 和 findstr ,执行效率相当。考虑到 call 和 goto 的使用有助于增加代码的可读性(尤其是对新手而言),在没有更好选择的情况下,建议使用 call 和 goto 。
依据坛友 @idwma 的建议,更改后的代码如下:- :identify_copy
- setlocal enabledelayedexpansion
- set "tmpdrctry=D:\newfolder"
- set strttm=%time%
- for /f "tokens=* delims=" %%z in ('dir /s/b/a-d-h-s') do (
- for /f "tokens=1" %%a in ('dir "%%z" /tc ^|findstr /e "%%~xz"') do (
- set "fpath=%%z"
- set "fdrctry=%%~dpz"
- set "fcd=%%a"
- if "!fcd!" GEQ "2022/01/01" (call set "tmpdrctry2=%%fdrctry:%cd%=%tmpdrctry%%%" &xcopy "!fpath!" "!tmpdrctry2!" /v/s)
- )
- )
- echo Process started at %strttm%, ended at %time%.
- pause
复制代码
.
=============== 以下为原帖内容 ===============
操作目标:复制当前文件夹中2022年1月1日之后创建的文件至指定文件夹(D:\newfolder),须保持目录树。
使用代码如下,因多次调用 call 和 goto,导致执行效率很低(总文件数约5000个)。
求教:如何提高执行效率。- :identify_copy
- set strttm=%time%
- set "tmpdrctry=D:\newfolder"
- for /f "tokens=* delims=" %%z in ('dir /s/b/a-d-h-s') do (
- set "fpath=%%z"
- set "fdrctry=%%~dpz"
- call :acqrdt
- )
- echo Process started at %strttm%, ended at %time%.
- pause
-
- :acqrdt
- for /f "skip=4 tokens=1" %%a in ('dir "%fpath%" /tc') do (
- set "fcd=%%a"
- call :dtprcss & goto :EOF
- )
-
- :dtprcss
- if "%fcd%" GEQ "2022/01/01" (goto copynf)
- goto :EOF
-
- :copynf
- call set "tmpdrctry2=%%fdrctry:%sdrctry%=%tmpdrctry%%%"
- xcopy "%fpath%" "%tmpdrctry2%" /v/s
- goto :EOF
复制代码
作者: idwma 时间: 2022-5-17 18:21
- xcopy . D:\newfolder /d:1-1-2022 /v/s
复制代码
作者: alredstone 时间: 2022-5-17 18:26
回复 2# idwma
xcopy 的 /d 参数是修改日期,不是创建日期。
作者: idwma 时间: 2022-5-17 18:32
- robocopy . D:\newfolder /maxage:20220101 /s
复制代码
作者: alredstone 时间: 2022-5-17 18:39
回复 4# idwma
robocopy 的 maxage 参数,也是修改日期
作者: idwma 时间: 2022-5-17 18:50
本帖最后由 idwma 于 2022-5-17 19:23 编辑
- setlocal enabledelayedexpansion
- set "tmpdrctry=D:\newfolder\"
- for /f "tokens=* delims=" %%z in ('dir /s/b/a-d-h-s') do (
- for /f "skip=4 tokens=1" %%a in ('dir "%%z" /tc') do (
- if "%%a" GEQ "2022/01/01" (
- set "fdrctry=%%~dpz"
- set "fdrctry=!fdrctry:%cd%=!"
- mkdir "%tmpdrctry%!fdrctry!"
- copy "%%z" "%tmpdrctry%!fdrctry!"
- )
- )
- )
复制代码
作者: alredstone 时间: 2022-5-17 21:31
本帖最后由 alredstone 于 2022-5-17 23:28 编辑
回复 6# idwma
说明一下,因对单个文件 dir 的 /tc 结果有 6 行,上述代码直接使用的话会出错,需要添加 |findstr /e "%%~xz"
总的来说,非常棒的思路,降低了call、goto的调用。
作者: alredstone 时间: 2022-5-17 23:27
尴尬的问题出现了,因为 管道 和 findstr 的使用,最终执行效率并没有改善
作者: idwma 时间: 2022-5-18 14:12
回复 7# alredstone
不加findstr也可以的吧, 出什么样的错?
作者: alredstone 时间: 2022-5-18 16:53
回复 9# idwma
对单个文件 dir /tc 输出结果一共有 6 行(不计空行),skip=4 只能跳过前 3 行,接着会将 4~6 行的结果赋值给 %%a,即同一个文件会赋值 3 次,导致出错。
这也是我采用的代码中获取创建日期的时候写为 call :dtprcss & goto :EOF 的原因。
对单个文件 dir /tc 输出的信息如下:- 驱动器属性
- 卷序号
-
- 文件所在目录
-
- 文件创建日期 时间 大小 文件名
- 目录内文件个数 大小
- 包含目录个数 卷剩余容量
复制代码
作者: qixiaobin0715 时间: 2022-5-18 17:03
6楼代码第5行难道是吃素的?不知楼主是否实际测试过。
作者: qixiaobin0715 时间: 2022-5-18 17:10
这种情况好像只能在源文本中测试,因为在备份文件中测试,创建时间就变成备份时的时间了。
作者: idwma 时间: 2022-5-18 17:22
第8行改一下应该不提示出错了吧- mkdir "%tmpdrctry%!fdrctry!" 2>nul
复制代码
作者: alredstone 时间: 2022-5-18 17:26
回复 11# qixiaobin0715
别着激动嘛
if "%%a" GEQ "2022/01/01" 这句是将 %%a 的值与字符串 2022/01/01 进行比较。在本帖讨论的条件下,对于每个文件而言 %%a 会被赋值 3 次,即后面的命令也会重复 3 次。
即除了 创建时间 会被赋值给 %%a 外,目录内的文件数、目录数同样也会被赋值给 %%a 并与字符串 2022/01/01 进行比较。因此会出错。
代码的鲁棒性(Robustness)也是一个需要考虑的因素。
作者: alredstone 时间: 2022-5-18 17:38
回复 13# idwma
这样也可以吧,也是一种解决思路。
作者: alredstone 时间: 2022-5-18 17:45
回复 12# qixiaobin0715
测试的时候将 dir /tc 改为 dir /tw (最后修改时间)就可以了。运行效率上不会有明显差别。
作者: qixiaobin0715 时间: 2022-5-19 08:51
回复 14# alredstone
我觉得你可能没有理解对。对于同一个文件来说,循环变量%%a可能会发生变化,而判断语句括号中的语句只会执行一次。而你所说的“错误”,就像 idwma 在13楼指出的那样,是mkdir命令的问题,有可能同一个文件夹中存在多个符合条件的文件,创建文件夹时有重名情况引起的。
作者: alredstone 时间: 2022-5-19 12:29
本帖最后由 alredstone 于 2022-5-19 12:58 编辑
回复 17# qixiaobin0715
您说的没错,判断语句括号中的语句只会执行一次。然而,对 %%a 的赋值是 for /f "skip=4 tokens=1" %%a in ('dir "%%z" /tc') 完成的,是在 if 语句之前。
因为 %%a 会被赋值 3 次, 所以 if "%%a" GEQ "2022/01/01" 这句会被执行 3 次。而这 3 次比对,会导致代码的鲁棒性不佳(比如日期格式为 MM/DD/YYYY 的系统里,就会报错),这是我在纠结的地方。
所以说,不是我没有理解 @idwma 坛友的代码,而是您可能没有理解 cmd 对 for /f + if 的转译规则。
题外话,关于 mkdir 命令创建重名文件夹报错的问题,处理起来很简单,删掉 mkdir 行,将 copy 改为 xcopy 命令就可以了。当然,@idwma 坛友直接关闭报错的方式,更加简单粗暴。
.
欢迎光临 批处理之家 (http://bbs.bathome.net/) |
Powered by Discuz! 7.2 |