如何在python中检测文件是否为二进制文件(非文本文件)?


7 Answers

另一种基于文件(1)行为的方法是

>>> textchars = bytearray({7,8,9,10,12,13,27} | set(range(0x20, 0x100)) - {0x7f})
>>> is_binary_string = lambda bytes: bool(bytes.translate(None, textchars))

例:

>>> is_binary_string(open('/usr/bin/python', 'rb').read(1024))
True
>>> is_binary_string(open('/usr/bin/dh_python3', 'rb').read(1024))
False
Question

如何判断一个文件是否是二进制文件(非文本)? 我正在通过python中的一大组文件进行搜索,并继续在二进制文件中获得匹配。 这使得输出看起来令人难以置信的混乱。

我知道我可以使用grep -I,但是我对数据的处理比grep允许的要多。

在过去,我只会搜索大于0x7f的字符,但是在现代系统中,utf8等等是不可能的。 理想情况下,解决方案会很快,但任何解决方案都可以。




你在unix吗? 如果是这样,那么试试:

isBinary = os.system("file -b" + name + " | grep text > /dev/null")

shell的返回值是相反的(0是好的,所以如果它找到“text”,那么它将返回0,在Python中是False表达式)。




如果有帮助,许多二进制类型都以幻数开头。 这是一个文件签名列表




使用binaryornot库( GitHub )。

这非常简单,并基于在此问题中找到的代码。

实际上你可以用2行代码编写这个代码,但是这个软件包不需要用跨平台的各种奇怪的文件类型编写和彻底测试这两行代码。




在* NIX:

如果您有权访问file shell命令,则shlex可以帮助使子进程模块更加可用:

from os.path import realpath
from subprocess import check_output
from shlex import split

filepath = realpath('rel/or/abs/path/to/file')
assert 'ascii' in check_output(split('file {}'.format(filepth).lower()))

或者,您也可以将其粘贴在for循环中,以使用以下命令获取当前目录中所有文件的输出:

import os
for afile in [x for x in os.listdir('.') if os.path.isfile(x)]:
    assert 'ascii' in check_output(split('file {}'.format(afile).lower()))

或所有的子目录:

for curdir, filelist in zip(os.walk('.')[0], os.walk('.')[2]):
     for afile in filelist:
         assert 'ascii' in check_output(split('file {}'.format(afile).lower()))



如果您使用的是带有utf-8的python3,那么它很简单,只需在文本模式下打开文件,并在遇到UnicodeDecodeError停止处理。 在文本模式下处理文件时(Python以二进制模式处理bytearray),Python3将使用unicode - 如果您的编码无法解码任意文件,则很可能会得到UnicodeDecodeError

例:

try:
    with open(filename, "r") as f:
        for l in f:
             process_line(l)
except UnicodeDecodeError:
    pass # Fond non-text data



我想最好的解决方案是使用guess_type函数。 它拥有多个mimetypes的列表,您也可以包含您自己的类型。 这里来了我解决我的问题的脚本:

from mimetypes import guess_type
from mimetypes import add_type

def __init__(self):
        self.__addMimeTypes()

def __addMimeTypes(self):
        add_type("text/plain",".properties")

def __listDir(self,path):
        try:
            return listdir(path)
        except IOError:
            print ("The directory {0} could not be accessed".format(path))

def getTextFiles(self, path):
        asciiFiles = []
        for files in self.__listDir(path):
            if guess_type(files)[0].split("/")[0] == "text":
                asciiFiles.append(files)
        try:
            return asciiFiles
        except NameError:
            print ("No text files in directory: {0}".format(path))
        finally:
            del asciiFiles

它是一个类的内部,你可以看到基于代码的结构。 但是你几乎可以改变你想在应用程序中实现的东西。 它使用起来相当简单。 方法getTextFiles返回一个列表对象,其中包含驻留在路径变量中传递的目录中的所有文本文件。




如果你不在Windows上,你可以使用Python Magic来确定文件类型。 然后你可以检查它是否是文本/ MIME类型。




Related