【问题标题】:How to identify the file content as ASCII or binary如何将文件内容识别为 ASCII 或二进制
【发布时间】:2010-09-21 14:36:05
【问题描述】:

如何使用 C++ 识别文件内容是 ASCII 还是二进制?

【问题讨论】:

标签: c++ ascii binaryfiles file-format


【解决方案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 是如何工作的;它有三种策略来确定文件的类型:

    根据您的平台以及您可能感兴趣的文件,您可以查看它的实现,甚至调用它。

    【讨论】:

      【解决方案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 检测二进制文件,而二进制文件又使用ICUcharset 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;
                }
                

                【讨论】:

                  猜你喜欢
                  • 2017-07-11
                  • 2019-02-13
                  • 2021-01-07
                  • 2015-03-13
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-01-16
                  相关资源
                  最近更新 更多