一位朋友有数千个文件,其中可能只包含 NULL(ASCII 0)。
(如果有兴趣,请参阅超级用户问答了解原因)。
这些文件的大小从 650 字节到 ~200MB 不等(大多数为 4-8MB)。
在 Windows 中,有什么方法可以快速确定哪些文件只包含 NULL,然后可以删除它们?
如果可能的话,最好使用内置的 Windows(7)工具。
我在想类似的事情:
findstr /m /s /r ^(\x00)+$ *.*
可以找到仅由 NULL 组成的文件,但在测试中,它不会返回任何结果。
更新 1:
我对此进行了更多实验,发现:
findstr /m /s /r [^\x00] *
可能正在努力寻找逆文件(不是仅包含NULL),这也可以用来达到目标。
但奇怪的是:
findstr /m /s /r [^\000] *
产生不同的结果。
因为十六进制 0(\x00
在正则表达式中)= 八进制 0(\000
在正则表达式中),所以我希望这两个命令得到相同的结果。
这让我怀疑这些命令中至少有一个的结果是否不正确。
更新 2:
嗯,看起来是这样的:
findstr /m /s /r [^\x00] *
可能会正常工作,并且事实是:
findstr /m /s /r [^\000] *
产生不同的结果很可能是微软的另一个错误(如果它们应该产生不同的结果,请纠正我,解释为什么这两个命令会产生不同的结果)。
我使用优秀的跨平台证实了这一点瑞士锉刀第三方工具。
初步测试揭示了 SFK 命令的结果:
sfk xfindbin . "/[byte not \x00]/" -names
与 匹配findstr /m /s /r [^\x00] *
,但不匹配findstr /m /s /r [^\000] *
。这让我相信我可能又发现了微软findstr
命令中的另一个错误(参见SS64了解该 Microsoft 工具中其他错误的摘要)。
更新 3:
进一步的测试揭示了SFK命令的结果:
sfk xfindbin . "/[byte not \x00]/" -names
findstr /m /s /r [^\x00] *
正确找到和未找到的一些文件findstr /m /s /r [^\000] *
。
答案1
我能够使用这个 power shell 脚本来找到没有内容或只有空值的文件:
$files = Get-ChildItem -Path c:\somepath\tostartfrom -Recurse -File
foreach ($f in $files){
$content = Get-Content -Path $f.FullName -TotalCount 10
if ($content -match '[\\x01-\\xFF]+') {
#do nothing as file has a valid character in it
}
else {Write-Output $f.FullName}
}
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
您可以使用
c:\test\ps\findnullfiles.ps1 | Out-File -FilePath c:\test\ps\results.txt
将信息发送到文本文件以供日后使用。在 else 子句中添加额外的测试,您可以根据需要跳过没有内容的文件。
答案2
解释情况:
在中FINDSTR
,/S
是递归的,/R
是正则表达式:使用它将给出匹配的行,而不是文件名。
因此我们必须使用/M
:来打印文件名,而不是匹配的行。
现在,给定的正则表达式是^(\x00)+$
括号“ (
”和“ )
”不是分组(像在 Perl 中)而是单个字符,因此在每个 NULL 文件中都没有任何匹配项。
另一个正则表达式是,[^\x00]
不是^
行首 ,而是字符类的否定。
它应该是^[\x00]
行首 ,假设支持搜索 NULL 字符。
同样,[^\000]
应该是^[\000]
,同样假设支持 NULL 字符。
不幸的是,FINDSTR
寻找空字符时不会给出正确的结果:
https://ss64.com/nt/findstr.html
“FINDSTR 无法搜索 Unicode 文件中常见的空字节。”
还有其他 BUGS。
解决方案1:
使用/X
(打印完全匹配的行)和正则表达式[\x00]+
或[\000]+
,将检查整行,假设FINDSTR
可以查看空字符。
解决方案2:
安装并使用PERL
,它将发挥神奇的作用。