如何将文件内容识别为 ASCII 或二进制
Posted
技术标签:
【中文标题】如何将文件内容识别为 ASCII 或二进制【英文标题】:How to identify the file content as ASCII or binary 【发布时间】:2010-09-21 14:36:05 【问题描述】:如何使用 C++ 识别文件内容是 ASCII 还是二进制?
【问题讨论】:
其他问题更好,所以建议关闭这个。重复***.com/questions/567757/… 【参考方案1】:如果文件只包含十进制字节 9–13、32–126,则它可能是纯 ASCII 文本文件。否则,它不是。但是,它可能仍然是另一种编码的文本。
如果在除了上述字节之外,该文件包含仅十进制字节 128–255,它可能是一个 8 位或变量的文本文件 -长度 基于 ASCII 的编码,例如 ISO-8859-1、UTF-8 或 ASCII+Big5。如果不是,出于某些目的,您可能可以在这里停下来并认为该文件是二进制文件。但是,它可能仍然是 16 位或 32 位编码的文本。
如果文件不符合上述限制,请检查文件的前 2-4 个字节是否有 byte-order mark:
如果前两个字节是十六进制FE FF
,则文件暂时是 UTF-16 BE。
如果前两个字节是十六进制FF FE
,而后面两个字节不是十六进制00 00
,则文件暂定为UTF-16 LE。
如果前四个字节是十六进制 00 00 FE FF
,则文件暂时是 UTF-32 BE。
如果前四个字节是十六进制 FF FE 00 00
,则文件暂时是 UTF-32 LE。
如果通过上面的检查,你已经确定了一个暂定编码,那么只检查下面对应的编码,以确保该文件不是碰巧匹配字节顺序标记的二进制文件。
如果您尚未确定暂定编码,则该文件可能仍是其中一种编码的文本文件,因为字节顺序标记不是强制性的,因此请检查以下列表中的所有编码:
如果文件仅包含十进制值为 9-13、32-126 和 128 或以上的大端双字节字,则该文件可能是 UTF-16 BE。李> 如果文件包含仅 little-endian 两字节字,十进制值为 9–13、32–126 和 128 或更高,则该文件可能是 UTF-16 LE。李> 如果文件仅包含十进制值为 9–13、32–126 和 128 或以上的大端四字节字,则该文件可能是 UTF-32 BE。李> 如果文件包含仅小端四字节字,十进制值为 9–13、32–126 和 128 或更高,则该文件可能是 UTF-32 LE。李>如果在所有这些检查之后,您仍然没有确定编码,则该文件不是我所知道的任何基于 ASCII 编码的文本文件,因此对于大多数用途,您可能会认为它是二进制文件(它可能仍然是非 ASCII 编码(例如 EBCDIC)的文本文件,但我怀疑这远远超出了您的关注范围)。
【讨论】:
这仅适用于文本为 ASCII 的情况。如果是 UTF16 或 UTF32,那么它可能包含值为 0-8、14-31 和 127 的字节。因此您的答案令人困惑。 @David Arno,没错,但问题实际上是关于 ASCII 与否。 @quinmars,我提请您注意这个答案的第一行“我假设您真的想检测文件是否是文本(以任何编码),而不仅仅是 ASCII。”。鉴于此,第二行是完全错误的。因此,答案令人困惑和误导。 @David Arno:我同意,所以我编辑了我的答案以反映您的 cmets。谢谢:)。 抱歉,Daniel,但系统不允许我撤消我的反对票,这很荒谬,因为您已经对其进行了编辑以使其成为一个非常好的答案:(【参考方案2】:您使用带有stream.get() 的普通循环遍历它,并检查您读取的字节值是否为<= 127
。多种方法中的一种:
int c;
std::ifstream a("file.txt");
while((c = a.get()) != EOF && c <= 127)
;
if(c == EOF)
/* file is all ASCII */
但是,正如有人提到的,所有文件毕竟都是二进制文件。此外,不清楚您所说的“ascii”是什么意思。如果你的意思是字符代码,那么这确实是你要走的路。但是,如果您仅指字母数字值,则需要另一种方法。
【讨论】:
我认为这不是作者的本意。但事实上这是正确的答案。 :-) 这是所提问题的正确答案。然而,Tomalak 你说得对,san 可能没有正确表达这个问题。 “ASCII 或二进制”这一表达暗示他的真正意思是“文本,而不是二进制”。 顺便说一句:“字母数字”只是文本的子集。 是的。也许他想要那个。但也许他也想包含 '['... 永远不知道 :)【参考方案3】:我的文本编辑器决定是否存在空字节。在实践中,这非常有效:没有空字节的二进制文件极为罕见。
【讨论】:
这也是 gnu diff 所做的。除了他们只查看文件中的预定义长度。 (不想为空字节浏览 4GB 文件...) 这也是“grep -I”的作用。【参考方案4】:每个文件的内容都是二进制的。所以,其他什么都不知道,你无法确定。
ASCII 是一个解释问题。如果你在文本编辑器中打开一个二进制文件,你就会明白我的意思。
大多数二进制文件都包含一个固定的标题(每种类型),您可以查找,或者您可以将文件扩展名作为提示。如果您需要 UTF 编码的文件,您可以查找字节顺序标记,但它们也是可选的。
除非你更仔细地定义你的问题,否则不可能有明确的答案。
【讨论】:
【参考方案5】:看看file command 是如何工作的;它有三种策略来确定文件的类型:
文件系统测试 magic number 测试 和语言测试根据您的平台以及您可能感兴趣的文件,您可以查看它的实现,甚至调用它。
【讨论】:
【参考方案6】:如果问题真的是如何仅检测 ASCII,那么 litb 的答案就是正确的。但是,如果 san 在知道如何确定文件是否包含文本之后,那么问题就会变得更加复杂。 ASCII 只是一种 - 越来越不受欢迎 - 表示文本的方式。 Unicode 系统 - UTF16、UTF32 和 UTF8 越来越受欢迎。从理论上讲,可以通过检查前两个字节是否为 unicocode 字节顺序标记 (BOM) 0xFEFF(如果字节顺序颠倒,则为 0xFFFE)来轻松测试它们。然而,由于这两个字节搞砸了 Linux 系统的许多文件格式,因此不能保证它们存在。此外,二进制文件可能以 0xFEFF 开头。
如果文件是 unicode,查找 0x00(或其他控制字符)也无济于事。如果文件是 UFT16,并且文件包含英文文本,那么每隔一个字符将是 0x00。
如果您知道将写入文本文件的语言,则可以分析字节并统计确定它是否包含文本。例如,英语中最常见的字母是 E 后跟 T。因此,如果文件包含的 E 和 T 比 Z 和 X 多得多,那么它很可能是文本。当然,有必要将其作为 ASCII 和各种 unicode 进行测试以确保。
如果文件不是用英文编写的——或者你想支持多种语言——那么剩下的两个选项就是查看 Windows 上的文件扩展名,并根据“magic file”数据库检查前四个字节" 代码来确定文件的类型,从而确定它是否包含文本。
【讨论】:
【参考方案7】:嗯,这取决于您对 ASCII 的定义。您可以检查 ASCII 码
您还可以检查常规换行符(0x10 或 0x13,0x10)以检测文本文件。
【讨论】:
【参考方案8】:要检查,您必须以二进制形式打开文件。您无法将文件作为文本打开。 ASCII 实际上是二进制的子集。 之后,您必须检查字节值。 ASCII 的字节值是 0-127,但 0-31 是控制字符。 TAB、CR 和 LF 是唯一常用的控制字符。 你不能(便携式)使用'A'和'Z';不能保证它们是ASCII(!)。 如果你需要它们,你必须定义。
const unsigned char ASCII_A = 0x41; // NOT 'A'
const unsigned char ASCII_Z = ASCII_A + 25;
【讨论】:
【参考方案9】:这个问题确实没有正确或错误的答案,只是复杂的解决方案不适用于所有可能的文本文件。
这是一个链接The Old New Thing Article,说明记事本如何检测 ascii 文件的类型。它并不完美,但看看微软如何处理它很有趣。
【讨论】:
【参考方案10】:Github's linguist 使用charlock holmes library 检测二进制文件,而二进制文件又使用ICU 的charset detection。
ICU 库可用于多种编程语言,包括 C 和 Java。
【讨论】:
【参考方案11】:bool checkFileASCIIFormat(std::string fileName)
bool ascii = true;
std::ifstream read(fileName);
int line;
while ((ascii) && (!read.eof()))
line = read.get();
if (line > 127)
//ASCII codes only go up to 127
ascii = false;
return ascii;
【讨论】:
以上是关于如何将文件内容识别为 ASCII 或二进制的主要内容,如果未能解决你的问题,请参考以下文章
PowerShell 该术语未被识别为 cmdlet 函数脚本文件或可运行程序
解决VScode安装Babel转码器报错:无法将“cnpm“项识别为cmdlet函数脚本文件或可运行程序的名称的问题
无法将“slmgr”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。如何解决?
tsc : 无法将“tsc”项识别为 cmdlet函数脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。