检测文件是二进制还是纯文本?

4

我怎样检测一个文件是二进制文件还是纯文本文件?

我的.NET应用程序正在处理批处理文件并提取数据,但我不想处理二进制文件。

作为解决方案,我考虑先分析文件的前X个字节,如果有更多的不可打印字符比可打印字符,则应该是二进制文件。

这是正确的方法吗?是否有更好的实现方法来执行此任务?


1
你的方法基本上是我会做的方式。我会扫描许多 \n,但是思路相同。 - Michael Dorgan
1
请查看https://dev59.com/pnRB5IYBdhLWcg3wn4fb或https://dev59.com/qHVC5IYBdhLWcg3wfhKL - 这些是相同的问题,只是不专门针对.NET,我认为您想知道的大部分内容已经在那里得到了回答。 - schnaader
你正在进行什么类型的处理? - Lasse V. Karlsen
@Lasse,这是提取文本的一部分(我有3-5个不同的模式),所以如果我使用二进制格式,那么意味着需要大量的处理能力来匹配内容。 - dr. evil
@schnaader 我搜索了一下,我想是因为我的忽略列表!找不到任何一个。 - dr. evil
4个回答

6
你所说的二进制是什么意思?“孙子兵法”对你来说是用中文二进制写的吗?那日英词典呢?
没有完全确定的方法。
你需要使用某种启发式方法。
一些选项可能是查看:
- 字节顺序标记 - 文件签名(也称为魔术数字) - 文件扩展名 如果上述方法(尤其是文件签名和扩展名)没有帮助,则可以根据特定字节的存在/不存在来猜测(就像你正在做的那样)。
注意:最好先检查扩展名/签名,因为你只需要读取几个字节/文件元数据,这比实际读取整个文件要有效率得多。

2
这就是我提出问题的原因 :) - dr. evil
元数据读取太多了,尽管你需要一个签名数据库等等,但对于我的任务来说,完全是过度工程化了。 - dr. evil
@dr. evil。进行文件扩展名检查不太合理吧?我认为那是文件元数据。无论如何,我想你已经有足够的信息来继续你的工作了 :-) - Aryabhatta
就像你所说的,我想我已经有足够的信息来开始了,可惜没有易于使用的.NET库来实现这个目的。 - dr. evil

5
Unix的file命令以巧妙的方式执行此操作。当然,它还可以做更多的事情,但您可以在这里检查算法,然后构建一些专门的东西。

更新:上面的链接似乎已经失效了。可以尝试this


1
这是否适用于在 Windows 环境下运行的 .Net 应用程序? - Aryabhatta
1
@Moron:是的,因为file不使用操作系统提供的信息来确定文件类型。它只是查看BOM、魔数、内容启发式等,正如其他答案中所述。 - Derrick Turk
@Derrick:我的意思是,它是否能检测到在Windows Vista/ Windows 7上常见的文件?无论如何,仅仅指向“file”的源代码并不真正有帮助。 - Aryabhatta
@Moron: 抱歉,提供完整的算法实现需要花费大量时间。file在其算法中是系统无关的,尽管源文件不是。我认为任何能够阅读C#代码的人都能理解一些C代码(因为它们类似),所以我认为你可以轻松找到与你相关的源代码部分。file非常可靠,可以最准确地告诉你所需的信息(二进制还是纯文本)。 - Bruno Brant
真的,一个现成的解决方案比自己实现要好。但是指向Unix C文件实现并不能在这方面提供帮助。如果你注意到了,我没有强烈反对你的答案,所以不会给你打负分 :-) - Aryabhatta

1

我认为最好的方法是从文件中最多取前X个字节(X可以是256、512等),计算未被ASCII文件使用的字符数(允许使用的ASCII代码为:10、13、32-126)。如果你确定脚本是用英语编写的,那么没有任何字符会超出上述集合。如果你不确定语言,那么你可以允许最多Y个字符超出该集合(如果X是512,我会选择Y为8或10)。

如果这还不够好,你可以使用更多的限制条件,例如:根据文件的语法,应该存在这样的关键词(例如:对于批处理文件,应该有一些echo、for、if、goto、call、exit等)。


0
你可以使用正则表达式匹配前X个字节,并且只有当所有字节都在正确的字符类中时才给出有效匹配。但这可能预设了你已经知道编码方式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接