如何用代码识别文件是 *文本文件* 还是 *二进制文件*,只能通过后缀名吗 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
daijinming
V2EX    程序员

如何用代码识别文件是 *文本文件* 还是 *二进制文件*,只能通过后缀名吗

  •  
  •   daijinming 2019-07-01 15:29:14 +08:00 6353 次点击
    这是一个创建于 2343 天前的主题,其中的信息可能已经有所发展或是发生改变。

    判断文本文件可以通过文件头,识别出是 UTF\GBK\或是 Unicode 什么的,但如何识别文本文件 还是 二进制文件 该怎么办?

    41 条回复    2019-07-02 08:50:31 +08:00
    Sylv
        1
    Sylv  
       2019-07-01 15:32:43 +08:00 via iPhone   3
    重新组织一下语言吧,你语文老师看到了应该会挺生气的。
    binux
        2
    binux  
       2019-07-01 15:34:47 +08:00
    不是 UTF\GBK\或是 Unicode 什么的就是二进制文件呗,多简单的事啊
    daijinming
        3
    daijinming  
    OP
       2019-07-01 15:37:06 +08:00
    @binux 不是这个意思,我是说判断文本文件采用哪种编码比较简单,但是区分 *文本文件* 和 *二进制*文件比较困难
    koebehshian
        4
    koebehshian  
       2019-07-01 15:38:07 +08:00
    参考文本编辑器的做法
    jasonyang9
        5
    jasonyang9  
       2019-07-01 15:39:53 +08:00   1
    daijinming
        6
    daijinming  
    OP
       2019-07-01 15:40:41 +08:00
    @koebehshian 记事本打开图片文件也是可以,不过显示的是乱码
    txy3000
        7
    txy3000  
       2019-07-01 15:40:43 +08:00
    你想以什么样的编码方式读取文件是由你决定的 文件都是 2 进制序列
    lotmany
        8
    lotmany  
       2019-07-01 15:41:24 +08:00
    哪些文件定义为二进制文件?哪些又是文本文件? 图片算二进制文件吗?不也是可以用文本编辑器打开.
    daijinming
        9
    daijinming  
    OP
       2019-07-01 15:42:09 +08:00
    @txy3000 二进制文件哪有编码呀,比如 图片,只要程序识别出无法显示出文本就好,而不是用乱码展示
    AlloVince
        10
    AlloVince  
       2019-07-01 15:42:20 +08:00   1
    `file --mime-type /path_to_your_file`
    binux
        11
    binux  
       2019-07-01 15:43:08 +08:00
    @daijinming 我意思是只要你能判断编码的就是文本文件,反之是二进制文件
    hacher
        13
    hacher  
       2019-07-01 15:46:11 +08:00   8
    git 是判断前 8000 字节是否含有"\x00"
    daijinming
        14
    daijinming  
    OP
       2019-07-01 15:48:04 +08:00
    @binux 理论上这么讲没问题,但是现有的网上的代码,都是这么判断 是不是 utf 编码,是不是 unicode 编码,... 还不是默认就是 ASCII 了,比如 https://blog.csdn.net/zh_geo/article/details/85859026
    yankebupt
        15
    yankebupt  
       2019-07-01 15:49:17 +08:00   1
    unicode 的有超出文本区字符的直接判二进制。非 unicode....么....
    上古时代(19xx)的判定方法是
    第 8 bit 占用率接近 40%-60%的算二进制,占用不到 5%的判文本.....中文非常用字超 25%的判二进制....其他看着随便判就是

    只适用于基本用途,因为....
    会误杀各种奇葩文件,纯色多的位图,各种冷门语言的文件等等各类文件...随便找个硬盘扫一下误判率不低于 5%...
    daijinming
        16
    daijinming  
    OP
       2019-07-01 15:49:27 +08:00
    @hacher 这个听着靠谱
    binux
        17
    binux  
       2019-07-01 15:52:05 +08:00
    @daijinming ASCII 才 128 个字符,是不是你自己不会判断吗,为什么要照着抄 ?
    pkookp8
        18
    pkookp8  
       2019-07-01 15:54:03 +08:00 via Android
    可以读到已知头的算已知格式
    其余全算二进制
    koebehshian
        19
    koebehshian  
       2019-07-01 15:55:11 +08:00
    @daijinming 我又没说记事本,记事本压根没有判断是文本文件还是二进制文件。我用 emeditor, 它可以
    daijinming
        20
    daijinming  
    OP
       2019-07-01 16:00:15 +08:00
    @hacher 包含 含有"\x00"就是二进制文件吗
    msg7086
        21
    msg7086  
       2019-07-01 16:01:31 +08:00   2
    什么叫文本文件,什么叫二进制文件,你先定义一下再问问题好吗?
    如果能以文本方式读取的都叫文本文件,那就是上面 @binux 说的,尝试以文本方式打开,不行就不是咯。

    如果没有具体定义的话,文本文件也可以称作二进制文件。反正都是二进制、十六进制存在电脑里的。
    怎么区分是「你」来决定的。

    随便举个例子。
    我们平时下载的种子文件,是用一种叫做 BEncode 的编码方式序列化的。
    比如一个数字 30,会编码成 i30e,一个字符串 abc 会编码成 3:abc。
    [1,'a']编码后就是 li1e1:ae。
    你说这算文本文件吗?
    但是种子里存的是文件的 hash,虽然编码结构都是文本,但是遇到 hash 的部分就很可能是二进制了。所以种子文件既可以算是文本文件,也可以算是二进制文件,而且并不能「识别」或者「区分」。

    包括有些位图文件,如果颜色正好能对应文本的话,一样可以用文本方式读取。

    历史上最著名的文本文件与二进制文件探测应用,是 FTP 协议里的传输方法。你可以用 TYPE I 切换成二进制传输,也可以用 TYPE A 切换成文本传输。至于后来人们因为文本文件类型误判而传坏了多少文件这个我就不多提了。
    msg7086
        22
    msg7086  
       2019-07-01 16:05:41 +08:00
    最传统的文本文件就是只包括 ASCII 可显示字符,即 0x20-0x7E。所以像中文啊日文啊这些全都不属于传统的文本文件范畴。特别是像 UTF-8 之类的,大幅利用 7bit 以外的区域、大量使用多字节编码的复杂系统,早就已经可以归属于「二进制文件」了。
    msg7086
        23
    msg7086  
       2019-07-01 16:13:21 +08:00   1
    总结一下。
    1. 什么是文本文件,什么是二进制文件,需要「你」来定义。
    2. 文本文件也是二进制文件。
    3. 现在不是文本文件的,以后可能会变成文本文件。

    关于 3,一个很常见的例子就是各种文字编码。
    上面提了一个 UTF-8,本来是一堆乱码的,但是只要有解码器,就能解码成字。
    还有包括 Windows 上很常见的 UTF-16 编码,正是用到了原先被认为只可能在二进制文件中出现的 0x00。
    而现在的一些无法被 UTF-16 解码、被你认为是二进制的格式,说不定就会被以后开始普及的 UTF-32 解码呢。
    你现在分辨出的二进制格式,很可能等新的解码方式出来以后,就可以被阐释成某种文本文件了。
    v2overflow
        24
    v2overflow  
       2019-07-01 16:13:59 +08:00 via iPhone
    文本文件就是二进制文件,如果文本规范的话,可以识别,主流的编码都有编码区间
    momo1999
        25
    momo1999  
       2019-07-01 16:32:46 +08:00
    chardet 一波
    hacher
        26
    hacher  
       2019-07-01 16:39:34 +08:00
    楼主的需求应该是区分文件是否纯 text 文件。只有文件包含'\x00'肯定不是纯文本~~
    jinliming2
        27
    jinliming2  
       2019-07-01 17:15:42 +08:00 via iPhone   1
    首先,所有文件都是二进制文件。
    我们常说的 UTF-8,GBK 之类的是文本编码,是将人可读的文本,按照特定的编码表转成二进制序列的一种方式,转成二进制序列之后就可以进行存储了。在读取的时候再按照原来的方式还原,就可以得到原始文本了。
    一般我们将这种把纯文本以特定编码存储的文件叫做纯文本文件。
    所以,纯文本文件有一个重要属性,就是编码。
    任何二进制文件都可以当作纯文本文件打开,只不过会显示为人不可读的字符序列,并且也确实都是字符!甚至使用部分编码打开显示的都是认识的字符(文化水平问题)。比如用 GBK 编码打开一张图片看看?你能说这张图片是纯文本文件吗?

    也就是说,任何文件都是二进制文件,当你将其赋予一种文本编码后,它就是一个文本文件。
    但这个编码不是随便给的,在有些编码里,特定的二进制序列是不会出现的,比如 0x00 几乎不会出现在任意编码规则里。所以,你可以通过猜测的方式去检查文件是否符合某个编码的规则,以此来确定是否为文本文件。
    至于要检测多少种编码,就看你的爱好了。甚至你可以自创一个文本编码,这个文本编码里可以出现 0x00,也不是不可以!
    Mithril
        28
    Mithril  
       2019-07-01 17:53:41 +08:00
    除非这文件是你自己写的,不然其他全是靠猜。
    你如何区分:用文本编辑器打开二进制文件时显示的乱码 和 故意写成乱码的文本文件
    就算你用编码范围限定也是会有误杀的,没什么万全的办法。
    soy
        29
    soy  
       2019-07-01 18:14:15 +08:00
    hx1997
        30
    hx1997  
       2019-07-01 18:33:48 +08:00
    @jinliming2 #24 一般说的“二进制文件”是与“文本文件”对立的,你非要说文本文件也是二进制也没错,但这不是通常的理解方式。你看维基百科: https://en.wikipedia.org/wiki/Binary_file
    "A binary file is a computer file that is not a text file."
    AX5N
        31
    AX5N  
       2019-07-01 18:39:33 +08:00
    @hx1997 你也说了,是“一般说”,大家都是理解计算机原理的人,还适用于一般这个概念吗?
    Mo0o
        32
    Mo0o  
       2019-07-01 18:41:42 +08:00
    不是,Linux 下,你把文件的一首歌的后缀名删点,你打开还是以音乐方式播放。
    hx1997
        33
    hx1997  
       2019-07-01 18:43:37 +08:00
    @AX5N #28 可以不杠吗? binary file 和 text file 的正常理解就是二元对立的,GNU diff 的手册里也是这么用的: https://www.gnu.org/software/diffutils/manual/html_node/Binary.html
    你的意思是 GNU 的人不懂计算机原理吗?
    zhangchioulin
        34
    zhangchioulin  
       2019-07-01 19:37:28 +08:00
    “可执行文件”是有“魔数”的。
    MeteorCat
        35
    MeteorCat  
       2019-07-01 19:39:07 +08:00 via Android
    mime 判断+1
    vkhsyj
        36
    vkhsyj  
       2019-07-01 19:48:58 +08:00
    后缀是不值得信任的东西,读一段内容看看能否解析成文本呗
    azh7138m
        37
    azh7138m  
       2019-07-01 19:49:36 +08:00
    @shuax py 的 chardet 判断文本的编码在文本不长(小几百字)的时候成功率非常低,尤其是有各种奇葩编码的时候,都是胡乱判断,everedit 判断都比它准。
    sikong31
        38
    sikong31  
       2019-07-01 20:11:03 +08:00
    文件都是二进制,要储存就是 1 和 0,你打开一个文件,指定 rt mode 就按默认编码解码文件,rb 就是直接读取。
    对于'文本文件'是什么编码,只有编码的人知道。
    zjsxwc
        39
    zjsxwc  
       2019-07-01 20:19:54 +08:00 via Android
    老早就有机构规定了二进制文件标准的,

    我之前的 mime type 探查器,正好也涉及,见代码:
    https://github.com/zjsxwc/mime-type-sniffer/blob/master/src/MimeTypeSniffer/MimeTypeSniffer.php#L316
    marshmallow
        40
    marshmallow  
       2019-07-01 22:36:50 +08:00
    unix 的 shell /usr/bin/file,你可以多试试几个文件,看看它都怎么判的
    daijinming
        41
    daijinming  
    OP
       2019-07-02 08:50:31 +08:00
    @zjsxwc 不错呦
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2500 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 04:40 PVG 12:40 LAX 20:40 JFK 23:40
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86