愚弄批量文件,并想知道为什么在以下情况下输出文件所需的时间差异很大:
场景1:简单遍历日志文件,并且每行始终使用第5个令牌,除非它包含过滤字符串。
(for /f "tokens=5" %%a in (test.log) do @echo(%%a) | findstr /v "filter_1 filter_2" > !filter!.txt
这很好用,通过50M文件在10秒内返回一个较小的10Mb文件。
场景2:完全相同,但在令牌的前端和末端添加内容,以便我可以输出为xml文件而不是文本文件。为此,我不得不重建一下,如下所示
echo ^<rows^> > test.xml
>>test.xml (
for /f "tokens=5" %%a in (
'findstr /v "filter1 filter2" test.log'
) do echo ^<r a="%%a"/^>
)
echo ^</rows^> >> test.xml
它可以按预期的方式用于小文件,但对于大文件来说就像永远一样。无论如何都可以通过方案2实现我想要的但使用方案1语法,因为这似乎更有效。
答案 0 :(得分:1)
FOR / F始终在开始任何迭代之前缓冲IN()子句的内容。这对于读取文件以及处理命令的输出都是如此。但是,我认为命令输出的缓冲方式存在一些根本区别,这使得大输出时速度特别慢。 修改: MC ND对why buffering of large output is so slow有一个很好的解释。
大多数人都惊讶地发现有时最快的批处理解决方案是将命令输出写入临时文件,然后使用FOR / F来读取临时文件。只要您的磁盘驱动器速度很快,这将很快。
我相信以下内容会大大加快速度:
findstr /v "filter1 filter2" test.log >test.log.mod
>test.xml (
echo ^<rows^>
for /f "tokens=5" %%A in (test.log.mod) do echo ^<r a="%%A"/^>
echo ^</rows^>
)
del test.log.mod
另一种选择是将XML包装器添加到原始管道的左侧,然后适当地修改FINDSTR过滤器。但是上述解决方案可能仍然会更快,具体取决于过滤掉的行数。
(
echo ^<rows^>
for /f "tokens=5" %%A in (test.log) do echo ^<r a="%%A"/^>
echo ^</rows^>
) | findstr /v /c:"modifiedFilter_1" /c:"modifiedFilter_2" > test.xml
如果过滤器是正则表达式,FINDSTR还需要/R
选项。
但更快的解决方案是使用像sed for Windows,或JScript / Batch混合实用程序,我的REPL.BAT或Aacini的FINDREPL.BAT。