首页 文章

如何区分'binary'和'text'文件?

提问于
浏览
57

非正式地,我们大多数人都知道存在“二进制”文件(目标文件,图像,电影,可执行文件,专有文档格式等)和“文本”文件(源代码,XML文件,HTML文件,电子邮件等) .

通常,您需要知道文件的内容才能对其执行任何有用的操作,并且如果编码是“二进制”或“文本”,则形成该视点,这并不重要 . 当然,文件只存储数据字节,因此它们都是“二进制”,而“文本”并不意味着什么,而不知道编码 . 然而,谈论'二进制'和'文本'文件仍然很有用,但为了避免冒犯任何具有这种不精确定义的人,我将继续使用'恐慌'报价 .

但是,有各种工具可以处理各种文件,实际上,您希望根据文件是“文本”还是“二进制”来执行不同的操作 . 这方面的一个例子是在控制台上输出数据的任何工具 . 简单的“文本”看起来很好,很有用 . '二进制'数据会扰乱您的终端,并且通常无法查看 . GNU grep在确定是否应该输出匹配到控制台时至少使用这种区别 .

那么,问题是,如何判断文件是'text'还是'binary'?而且要进一步限制,你如何在类似Linux的文件系统上讲述?我不知道任何文件系统元数据指示文件的'type',所以通过检查文件的内容,我怎么知道它是如何判断它是'text'还是'binary'?为简单起见,我们将'text'限制为可在用户控制台上打印的字符 . 特别是你会如何实现这个? (我认为这是暗示在这个网站上,但我想一般来说,指向现有的代码,这应该是有用的,我应该指定),我不是真的在我可以使用的现有程序之后做什么这个 .

11 回答

  • 1

    我公司制作的电子表格软件可以读取多种二进制文件格式以及文本文件 .

    我们首先看一下我们认识到的magic number的前几个字节 . 如果我们不识别我们读取的任何二进制类型的幻数,那么我们查看文件的前2K字节,看它是否是UTF-8UTF-16或当前编码的文本文件code page主机操作系统 . 如果它没有通过这些测试,我们假设它不是我们可以处理的文件并抛出适当的异常 .

  • 1

    您可以使用 file 命令 . 它对文件( man file )进行了大量测试,以确定它是二进制还是文本 . 如果需要从C开始,可以查看/借用其源代码 .

    file README
    README: ASCII English text, with very long lines
    
    file /bin/bash
    /bin/bash: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.5, dynamically linked (uses shared libs), stripped
    
  • 62

    您可以使用确定文件的MIME type

    file --mime FILENAME
    

    简写是Linux上的 file -i 和macOS上的 file -I (大写i)(见注释) .

    如果以 text/ 开头,则为文本,否则为二进制 . 唯一的例外是XML应用程序 . 您可以通过在文件类型的末尾查找 +xml 来匹配这些 .

  • 12

    好吧,如果你只是检查整个文件,看看每个字符是否都可以用 isprint(c) 打印 . 它对Unicode来说有点复杂 .

    要区分unicode文本文件,MSDN offers some great advice as to what to do .

    它的要点是首先检查前四个字节:

    EF BB BF     UTF-8 
    FF FE        UTF-16, little endian 
    FE FF        UTF-16, big endian 
    FF FE 00 00  UTF-32, little endian 
    00 00 FE FF  UTF-32, big-endian
    

    那会告诉你编码 . 然后,您希望将 iswprint(c) 用于文本文件中的其余字符 . 对于UTF-8和UTF-16,您需要手动解析数据,因为单个字符可以由可变数量的字节表示 . 此外,如果您希望使用 iswprint 的区域设置变体(如果您的平台上可用) .

  • 1

    Perl有一个不错的启发式 . 使用 -B 运算符测试二进制(及其相反, -T 以测试文本) . 这是shell一行列出文本文件:

    $ find . -type f -print0 | perl -0nE 'say if -f and -s _ and -T _'
    

    (请注意,没有前一美元的下划线是正确的(RTFM) . )

  • 13

    大多数尝试分辨差异的程序都使用启发式方法,例如检查文件的前n个字节,并查看这些字节是否符合'text'(即,它们是否都属于可打印的ASCII字符范围内) . 对于更好的干扰,在UNIX类系统上有's always the ' file'命令 .

  • 3

    这是一个古老的话题,但也许有人会觉得这很有用 . 如果必须在脚本中决定是否有某些内容文件然后你可以这样做:

    if file -i $1 | grep -q text;
    then 
    .
    .
    fi
    

    这将获取文件类型,并使用静默grep您可以决定它是否为文本 .

  • 2

    一个简单的检查是它是否有 \0 个字符 . 文本文件没有它们 .

  • 2

    如前所述* nix操作系统在file命令中具有此功能 . 此命令使用配置文件来定义许多流行文件结构中包含的幻数 .

    这个名为magic的文件历史上存储在/ etc中,尽管在某些发行版中可能位于/ usr / share中 . 魔术文件定义已知存在于文件中的值的偏移量,然后可以检查这些位置以确定文件的类型 .

    魔术文件的结构和描述可以通过查阅相关手册页(man magic)找到

    至于一个实现,可以在file.c本身找到,但是文件命令的相关部分确定它是否是可读文本是以下

    /* Make sure we are dealing with ascii text before looking for tokens */
        for (i = 0; i < nbytes - 1; i++) {
            if (!isascii(buf[i]) ||
                (iscntrl(buf[i]) && !isspace(buf[i]) &&
                 buf[i] != '\b' && buf[i] != '\032' && buf[i] != '\033'
                )
               )
                return 0;   /* not all ASCII */
        }
    
  • 4

    您可以使用 libmagic 这是Unix file 命令行的库版本 .

    有许多语言的包装:

  • 1

    要列出当前目录/子目录中的文本文件名:

    $ grep -rIl ''
    

    二进制文件:

    $ grep -rIL ''
    

    要检查特定文件,请稍微修改命令:

    $ grep -qI '' FILE
    

    然后,退出状态'0'表示文件是文本; '1' - 二进制 . 可以检查:

    $ echo $?

相关问题