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

gri*_*eve 96 python binary file

如何在python中判断文件是否为二进制(非文本)?我在python中搜索大量文件,并继续在二进制文件中获取匹配.这使得输出看起来非常混乱.

我知道我可以使用grep -I,但是我使用的数据比grep允许的更多.

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

jfs*_*jfs 56

另一种基于file(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))
Run Code Online (Sandbox Code Playgroud)

例:

>>> is_binary_string(open('/usr/bin/python', 'rb').read(1024))
True
>>> is_binary_string(open('/usr/bin/dh_python3', 'rb').read(1024))
False
Run Code Online (Sandbox Code Playgroud)

  • 有趣的是,file(1) 本身也不考虑 0x7f,所以从技术上讲,你应该使用 `bytearray([7,8,9,10,12,13,27]) + bytearray(range(0x20, 0x7f) ) + bytearray(range(0x80, 0x100))`代替。请参阅 [Python, file(1) - 为什么数字 \[7,8,9,10,12,13,27\] 和 range(0x20, 0x100) 用于确定文本与二进制文件](http:// stackoverflow.com/q/32184809) 和 https://github.com/file/file/blob/b52ef6e698a2098afb32d13ace50a78f0f0f0af4/src/encoding.c#L151-L228 (2认同)
  • @MartijnPieters:谢谢。我已经更新了答案以排除 `0x7f` (`DEL`) 。 (2认同)
  • @MarkRansom 要确保文件已关闭,请使用“with”语句或显式调用“.close()”方法。 (2认同)

Gav*_*Roy 37

您还可以使用mimetypes模块:

import mimetypes
...
mime = mimetypes.guess_type(file)
Run Code Online (Sandbox Code Playgroud)

编译二进制mime类型列表相当容易.例如,Apache使用mime.types文件进行分发,您可以将其解析为一组列表,二进制文本和文本,然后检查mime是否在您的文本或二进制列表中.

  • 有没有办法让`mimetypes`使用文件的内容而不仅仅是它的名字? (14认同)
  • 这不是一个很好的答案,因为mimetypes模块不适合所有文件.我正在查看一个文件,现在哪个系统`file`报告为"UTF-8 Unicode文本,行很长",但mimetypes.gest_type()将返回(None,None).此外,Apache的mimetype列表是白名单/子集.它绝不是一个完整的mimetypes列表.它不能用于将所有文件分类为文本或非文本. (5认同)
  • @intuited不,但是libmagic做到了.通过[python-magic](https://github.com/ahupp/python-magic)使用它. (4认同)
  • guess_types 基于文件扩展名,而不是像 Unix 命令“file”那样的真实内容。 (2认同)

sky*_*ing 12

如果你正在使用带有utf-8的python3,它是直接的,只需在文本模式下打开文件,如果你得到一个就停止处理UnicodeDecodeError.Python3将在文本模式下处理文件时使用unicode(以及二进制模式下的bytearray) - 如果您的编码无法解码任意文件,则很可能会得到UnicodeDecodeError.

例:

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

  • 为什么不直接使用`with open(filename,'r',encoding='utf-8') as f`? (2认同)

小智 10

试试这个:

def is_binary(filename):
    """Return true if the given filename is binary.
    @raise EnvironmentError: if the file does not exist or cannot be accessed.
    @attention: found @ http://bytes.com/topic/python/answers/21222-determine-file-type-binary-text on 6/08/2010
    @author: Trent Mick <TrentM@ActiveState.com>
    @author: Jorge Orpinel <jorge@orpinel.com>"""
    fin = open(filename, 'rb')
    try:
        CHUNKSIZE = 1024
        while 1:
            chunk = fin.read(CHUNKSIZE)
            if '\0' in chunk: # found null byte
                return True
            if len(chunk) < CHUNKSIZE:
                break # done
    # A-wooo! Mira, python no necesita el "except:". Achis... Que listo es.
    finally:
        fin.close()

    return False
Run Code Online (Sandbox Code Playgroud)

  • -1将"二进制"定义为包含零字节.将UTF-16编码的文本文件归类为"二进制". (7认同)
  • @John Machin:有趣的是,`git diff`实际上[以这种方式工作](http://git.kernel.org/?p=git​​/git.git;a=blob;f=xdiff-interface.c;h= e1e054e4d982de30d8a9c8c4109c6d62448f62a9; hb = HEAD#l240),果然,它将UTF-16文件检测为二进制文件. (5认同)
  • -1 - 我不认为“包含零字节”是对二进制与文本的充分测试,例如我可以创建一个包含所有 0x01 字节或重复 0xDEADBEEF 的文件,但它不是文本文件。基于 file(1) 的答案更好。 (2认同)

Sha*_*son 8

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

  • 不幸的是,“不以已知的幻数开头”并不等同于“是一个文本文件”。 (3认同)

Jac*_*son 6

这是一个使用Unix 文件命令的建议:

import re
import subprocess

def istext(path):
    return (re.search(r':.* text',
                      subprocess.Popen(["file", '-L', path], 
                                       stdout=subprocess.PIPE).stdout.read())
            is not None)
Run Code Online (Sandbox Code Playgroud)

用法示例:

>>> istext('/etc/motd') 
True
>>> istext('/vmlinuz') 
False
>>> open('/tmp/japanese').read()
'\xe3\x81\x93\xe3\x82\x8c\xe3\x81\xaf\xe3\x80\x81\xe3\x81\xbf\xe3\x81\x9a\xe3\x81\x8c\xe3\x82\x81\xe5\xba\xa7\xe3\x81\xae\xe6\x99\x82\xe4\xbb\xa3\xe3\x81\xae\xe5\xb9\x95\xe9\x96\x8b\xe3\x81\x91\xe3\x80\x82\n'
>>> istext('/tmp/japanese') # works on UTF-8
True

它有不能移植到Windows的缺点(除非你有像file命令那样的东西),并且必须为每个文件生成一个外部进程,这可能不太合适.

  • 类型错误:不能在类似字节的对象上使用字符串模式 (2认同)

小智 6

我们可以使用 python 本身来检查文件是否是二进制文件,因为如果我们尝试以文本模式打开二进制文件,它会失败

def is_binary(file_name):
    try:
        with open(file_name, 'tr') as check_file:  # try open file in text mode
            check_file.read()
            return False
    except:  # if fail then file is non-text (binary)
        return True
Run Code Online (Sandbox Code Playgroud)

  • AVI 视频文件不是二进制的吗?或者您是说某些 AVI 文件从 is_binary() 获得 False 返回值? (3认同)

Eat*_*oes 6

尝试使用当前维护的python-magic,它与 @Kami Kisiel 的答案中的模块不同。这确实支持包括 Windows 在内的所有平台,但您将需要libmagic二进制文件。自述文件中对此进行了解释。

与mimetypes模块不同,它不使用文件的扩展名,而是检查文件的内容。

>>> import magic
>>> magic.from_file("testdata/test.pdf", mime=True)
'application/pdf'
>>> magic.from_file("testdata/test.pdf")
'PDF document, version 1.2'
>>> magic.from_buffer(open("testdata/test.pdf").read(1024))
'PDF document, version 1.2'
Run Code Online (Sandbox Code Playgroud)


gue*_*tli 5

使用binaryornot库(GitHub).

它非常简单,基于此stackoverflow问题中的代码.

实际上你可以用两行代码来编写这个代码,但是这个包可以让你不必编写和彻底测试那两行代码和各种奇怪的文件类型,跨平台.


小智 5

from binaryornot.check import is_binary
is_binary('filename')
Run Code Online (Sandbox Code Playgroud)

文档


归档时间:

查看次数:

56264 次

最近记录:

6 年,2 月 前