在Windows上,文件扩展名通常是不够好:
# all C# and related files (projects, source control metadata, etc)
dir -r -fil *.cs* | ss foo
# exclude the binary types most likely to pollute your development workspace
dir -r -exclude *exe, *dll, *pdb | ss foo
# stick the first three lines in your $profile (refining them over time)
$bins = new-list string
$bins.AddRange([string[]]@("exe", "dll", "pdb", "png", "mdf", "docx"))
function IsBin([System.IO.FileInfo]$item) { !$bins.Contains($item.extension.ToLower()) }
dir -r | ? { !IsBin($_) } | ss foo
当然不过,文件扩展名是不完美的。没有人喜欢打字长名单,并且大量文件无论如何都是错误的。
我不认为Unix在文件系统中有任何特殊的二进制文本指示器。 (好吧,VMS的确如此,但我怀疑这是你的grep习惯的根源。)我看了一下Grep -I的实现,显然它只是基于文件第一部分的快速n-dirty启发式。原来这是一个我有a bit of experience的策略。所以这里是我的建议,选择适合Windows文本文件的启发式功能:
- 检查至少1KB的文件。很多文件格式都以一个看起来像文本的标题开头,但不久之后就会破解你的解析器。现代硬件的工作方式,读取50字节与读取4KB大致相同的I/O开销。
- 如果你只关心直线ASCII,只要看到字符范围外的内容[31-127加上CR和LF]就退出。您可能会意外地排除一些聪明的ASCII艺术,但试图将这些情况与二进制垃圾分开是非平凡的。
- 如果你想处理Unicode文本,让MS库处理肮脏的工作。这比你想象的更难。从Powershell您可以轻松访问静态方法(.NET)IMultiLang2 interface(COM)或Encoding.GetEncoding。当然,他们仍然只是猜测。雷蒙德对Notepad detection algorithm(以及迈克尔卡普兰内部的链接)的评论值得重新审视,然后再决定你想如何混合&匹配平台提供的库。
- 如果结果很重要 - 即一个缺陷会造成比糟糕的grep控制台更糟糕的事情 - 那么为了准确起见,不要害怕对某些文件扩展名进行硬编码。例如,* .PDF文件尽管是二进制格式,但偶尔也会有几KB的文本,导致上面链接的臭名昭着的错误。同样,如果您的文件扩展名可能包含XML或类似XML的数据,则可以尝试类似于Visual Studio's HTML editor的检测方案。 (SourceSafe 2005实际上在某些情况下借用了此算法)
- 无论发生什么事,都要制定合理的备份计划。
作为一个例子,这里的快速检测ASCII:
function IsAscii([System.IO.FileInfo]$item)
{
begin
{
$validList = new-list byte
$validList.AddRange([byte[]] (10,13))
$validList.AddRange([byte[]] (31..127))
}
process
{
try
{
$reader = $item.Open([System.IO.FileMode]::Open)
$bytes = new-object byte[] 1024
$numRead = $reader.Read($bytes, 0, $bytes.Count)
for($i=0; $i -lt $numRead; ++$i)
{
if (!$validList.Contains($bytes[$i]))
{ return $false }
}
$true
}
finally
{
if ($reader)
{ $reader.Dispose() }
}
}
}
我针对的使用模式是与“目录”,“SS”的管道插入其中,宾语从句。还有其他方法,这取决于您的脚本风格。
沿着一条建议路径改进检测算法留给读者。
编辑:我开始回答在我自己的评论您的评论,但它得到了太久......
以上,我看着这个问题从白名单已知良好序列的POV。在我所维护的应用程序中,错误地将二进制文件存储为文本的后果远比反之亦然。对于选择使用哪种FTP传输模式或要发送到电子邮件服务器的MIME编码类型等情况也是如此。在其他情况下,将明显虚假列入黑名单并允许其他所有内容都是黑名单所谓的文本是一个同样有效的技术。虽然U + 0000是一个有效的代码点,但它在现实世界中几乎找不到。同时,\ 00在结构化二进制文件中很常见(即每当固定字节长度的字段需要填充时),因此它成为一个非常简单的黑名单。 VSS 6.0单独使用此检查并确定。
另外:* .zip文件是检查\ 0风险较高的一种情况。与大多数二进制文件不同,它们的结构化“标题”(页脚?)块在结尾,而不是开头。假设理想的熵压缩,前1KB中无\ 0的机会是(1-1/256)^ 1024或大约2%。幸运的是,只需扫描其余的4KB群集NTFS读取操作,就可以将风险降低到0.00001%,而无需更改算法或编写其他特例。
要排除无效的UTF-8,请将\ C0-C1和\ F8-FD和\ FE-FF(一旦您搜索到可能的物料清单后)添加到黑名单。非常不完整,因为你实际上没有验证序列,但足够接近你的目的。如果你想获得更多的发现,现在是时候调用其中一个平台库,比如IMultiLang2 :: DetectInputCodepage。
不知道为什么\ C8(200十进制)在Grep的名单上。这不是一个超长的编码。例如,序列\ C8 \ 80代表Ȁ(U + 0200)。也许是特定于Unix的东西。
不是PS脚本,而是`findstr`等价的是`findstr/p`,我在PowerShell控制台中使用这样的:`doskey fs = findstr/spin/a:4A $ *`然后像`fs` –
orad
2014-05-21 20:18:42