您对 FOR 循环有误。只要您不使用 /R 选项,它就非常快。(我在 XP、Vista 和 Windows 7 上测试过)
我创建了一个包含 20,000 个文件的测试目录并运行以下脚本 - 它打印出第 10 个文件并在眨眼间完成:
@echo off
set n=0
for %%F in (*) do (
echo %%F
set /a "n+=1, 1/(10-n)" 2>nul || goto :break
)
:break
我通过故意除以 0 来检测何时达到 10 个文件以生成错误。我本可以使用延迟扩展并测试计数器的值,但%%F
如果文件名包含!
字符并且启用了延迟扩展,则无法正确打印。
因此,与您的看法相反,一个简单的 FOR 不会在迭代循环之前收集所有值。
您可能对 FOR /F 变体感到困惑:for /f "delims=" %%F in ('dir /b /a-d *') do ...
. 在这种情况下,DIR 命令在其自己的 shell 中执行,并且在任何 FOR 迭代之前获得整个结果集。
使用 FOR 解决方案需要注意的一件事 - FOR /R 选项似乎有可能减慢速度。我修改了上面的脚本以使用 /R 选项,然后在我的C:\
根目录上运行它。它很快打印了它找到的前 10 个文件,但随后似乎挂了很长时间,然后终于完成了。我不知道如何证明这一点,但我认为 FOR 循环正在浪费时间迭代我C:
驱动器上的所有目录,即使它没有对它们做任何事情。
编辑
我刚刚阅读了 PA. 对原始问题的评论。他有一个很好的观点——在某种程度上,FOR 和 DIR 都必须读取整个目录,以便执行隐式排序操作以正确顺序返回文件。但是,他也指出这是在非常低的水平上完成的。我的观点是 FOR 命令在开始迭代之前不需要等待所有值都返回(或为此而跳出循环)。
编辑 2
FOR /F 行为可能是福也可能是祸。对于这个应用程序,这是一个诅咒。但有时您在处理目录时会更改目录的内容。FOR /F 变体可防止您看到命令启动后发生的任何更改。简单的 FOR 命令有时可以在开始迭代后看到目录内容的变化。
FOR 命令以块的形式缓冲迭代 - 它会迭代它在缓冲区中的所有文件,但是当缓冲区为空并返回操作系统以获取下一个块时,它可以看到目录发生的更改. 这是一个演示该行为的测试脚本:
@echo off
md myTemp
for /l %%N in (1001 1 6000) do echo a>myTemp\%%N.txt
for /f %%N in ('dir /b myTemp\* ^| find /c /v ""') do Echo Starting with %%N files
set cnt=0
(
for %%F in (myTemp\*) do (
echo %%F
del /q myTemp\* 2>nul
set /a cnt+=1
)
)> test_for.out
echo Only %cnt% files were listed by FOR
echo(
for /l %%N in (1001 1 6000) do echo a>myTemp\%%N.txt
for /f %%N in ('dir /b myTemp\* ^| find /c /v ""') do Echo Starting with %%N files
set cnt=0
(
for /f %%F in ('dir /b /a-d myTemp\*') do (
echo %%F
del /q myTemp\* 2>nul
set /a cnt+=1
)
)> test_for_f.out
echo All %cnt% files were listed by FOR /F
rd myTemp
结果如下:
Starting with 5000 files
Only 743 files were listed by FOR
Starting with 5000 files
All 5000 files were listed by FOR /F
两个循环都从 5000 个文件开始,并在第一次迭代后删除所有文件。FOR /F 仍会处理启动时目录中的所有 5000 个文件名。FOR 仅处理适合缓冲区的 743 个文件名。
注意:我在 Windows 7 上获得了上述结果。我还在 Vista 和 XP 上进行了测试,除了在 FOR 循环中仅列出 35 个文件而不是 743 个文件之外,结果都相同。