programing

Python에서 파일이 바이너리(비텍스트)인지 확인하려면 어떻게 해야 합니까?

oldcodes 2023. 9. 6. 22:18
반응형

Python에서 파일이 바이너리(비텍스트)인지 확인하려면 어떻게 해야 합니까?

Python에서 파일이 이진(비텍스트)인지 어떻게 알 수 있습니까?

파이썬에서 많은 파일을 검색하고 있는데 바이너리 파일에서 일치하는 파일이 계속 나옵니다.이로 인해 출력이 엄청나게 지저분하게 보입니다.

내가 사용할 수 있다는 걸 알아요.grep -I보다 더 . . . . grep . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

과거에는 그냥 더 큰 캐릭터를 검색했을 것입니다.0x7f,그렇지만utf8현대 시스템에서는 불가능하게 만드는 것 같은 것들이 있습니다.이상적으로, 해결책은 빠를 것입니다.

파일(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

mim type 모듈을 사용할 수도 있습니다.

import mimetypes
...
mime = mimetypes.guess_type(file)

이진 마임 유형 목록을 작성하는 것은 상당히 쉽습니다.예를 들어 Apache는 mime.types 파일을 배포하여 목록, 바이너리 및 텍스트 세트로 구문 분석한 다음 Mime이 텍스트 또는 바이너리 목록에 있는지 확인할 수 있습니다.

를 사용하는 입니다. 과 python3과 python3과 python3이 있으면 를 중지하십시오. 텍스트 모드에서 파일을 열고 만약 당신이 utf-8을 얻는다면 처리를 중단하세요.UnicodeDecodeError때로 파일을 처리할 수 을 디코딩할 수 .Python3는 파일을 다운로드할 것입니다. 인코딩이 임의 파일을 디코딩할 수 없는 경우 다음을 얻을 가능성이 높습니다.UnicodeDecodeError.

예:

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

시도해 보기:

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

도움이 된다면, 많은 이진법들이 마법의 숫자로 시작합니다.여기 파일 서명 목록이 있습니다.

이진 또는 not 라이브러리(GitHub)를 사용합니다.

이 스택 오버플로 질문에서 발견된 코드를 기반으로 매우 간단합니다.

당신은 실제로 이것을 2줄의 코드로 쓸 수 있지만, 이 패키지는 당신이 모든 종류의 이상한 파일 형식, 크로스 플랫폼을 가진 2줄의 코드를 쓰고 철저하게 테스트할 필요가 없도록 해줍니다.

텍스트 모드에서 이진 파일을 열려고 하면 실패하기 때문에 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

유닉스 파일 명령어를 사용하는 제안은 다음과 같습니다.

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)

사용 예시:

>>> istext(/etc/motd')진실의>>> istext(/vmlinuz')거짓의>>> open('/tmp/일본어'). 읽기()'\xe3\x81\x93\xe3\x8c\xe3\x81\xaf\xe3\x80\x81\xbf3\x81\x9a\x8c\x81\xe3\x81\x8c\x81\xbf3\x9a\x8a3\x8c\x81\x8a3\x8c\x81\x8a5\x998\xe6\x82\xbb4\xa3\x8c\x8b3\x91\x80\n'>>> istext('/tmp/일본어') # UTF-8에서 작동합니다.진실의

이 이 과 할 이 과 할 이 file명령)을 입력하고, 각 파일에 대해 외부 프로세스를 생성해야 하므로, 이 프로세스는 입맛에 맞지 않을 수 있습니다.

from binaryornot.check import is_binary
is_binary('filename')

문서화

보통은 맞혀야 돼요.

파일에 확장자가 있으면 하나의 단서로 볼 수 있습니다.

알고 있는 이진 형식을 인식하고 이를 무시할 수도 있습니다.

그렇지 않으면 인쇄할 수 없는 ASCII 바이트의 비율을 확인하고 이로부터 추측합니다.

또한 UTF-8에서 디코딩을 시도해 볼 수 있으며 이를 통해 합리적인 출력이 나오는지 확인할 수 있습니다.

UTF-16 경고와 함께 더 짧은 해결책:

def is_binary(filename):
    """ 
    Return true if the given filename appears to be binary.
    File is considered to be binary if it contains a NULL byte.
    FIXME: This approach incorrectly reports UTF-16 as binary.
    """
    with open(filename, 'rb') as f:
        for block in f:
            if b'\0' in block:
                return True
    return False

@Kami Kisiel의 답변과 동일한 모듈이 아닌 현재 유지되는 python-magic을 사용해 보십시오.이것은 윈도우를 포함한 모든 플랫폼을 지원하지만, 당신이 필요로 할 것입니다.libmagicREADME에서 설명하고 있습니다.

mim type 모듈과 달리 파일의 확장자를 사용하지 않고 파일의 내용을 검사합니다.

>>> 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'

Windows(윈도우)가 아닌 경우 Python Magic(파이썬 매직)을 사용하여 파일 형식을 확인할 수 있습니다.그러면 텍스트/마임 타입인지 확인할 수 있습니다.

파일이 BOM으로 시작하는지 먼저 확인하고, 시작하지 않으면 초기 8192바이트 이내의 0바이트를 찾습니다.

import codecs


#: BOMs to indicate that a file is a text file even if it contains zero bytes.
_TEXT_BOMS = (
    codecs.BOM_UTF16_BE,
    codecs.BOM_UTF16_LE,
    codecs.BOM_UTF32_BE,
    codecs.BOM_UTF32_LE,
    codecs.BOM_UTF8,
)


def is_binary_file(source_path):
    with open(source_path, 'rb') as source_file:
        initial_bytes = source_file.read(8192)
    return not any(initial_bytes.startswith(bom) for bom in _TEXT_BOMS) \
           and b'\0' in initial_bytes

기술적으로 UTF-8 BOM은 모든 실용적인 목적을 위해 0바이트를 포함해서는 안 되기 때문에 검사는 불필요합니다.그러나 매우 일반적인 인코딩이므로 8192바이트를 모두 스캔하여 0으로 만드는 것보다 처음에 BOM을 확인하는 것이 더 빠릅니다.

대부분의 프로그램은 NULL 문자를 포함하는 경우 파일을 이진 파일("라인 지향"이 아닌 파일)로 간주합니다.

의 은 과 과 는 다음과 같습니다.pp_fttext()(pp_sys.c)은 파이썬에 구현되어 있습니다.

import sys
PY3 = sys.version_info[0] == 3

# A function that takes an integer in the 8-bit range and returns
# a single-character byte object in py3 / a single-character string
# in py2.
#
int2byte = (lambda x: bytes((x,))) if PY3 else chr

_text_characters = (
        b''.join(int2byte(i) for i in range(32, 127)) +
        b'\n\r\t\f\b')

def istextfile(fileobj, blocksize=512):
    """ Uses heuristics to guess whether the given file is text or binary,
        by reading a single block of bytes from the file.
        If more than 30% of the chars in the block are non-text, or there
        are NUL ('\x00') bytes in the block, assume this is a binary file.
    """
    block = fileobj.read(blocksize)
    if b'\x00' in block:
        # Files with null bytes are binary
        return False
    elif not block:
        # An empty file is considered a valid text file
        return True

    # Use translate's 'deletechars' argument to efficiently remove all
    # occurrences of _text_characters from the block
    nontext = block.translate(None, _text_characters)
    return float(len(nontext)) / len(block) <= 0.30

또한 이 코드는 Python 2와 Python 3 모두에서 변경 없이 실행되도록 작성되었습니다.

출처: Python에 구현된 Perl의 "파일이 텍스트인지 이진인지 추측"

저는 정확히 같은 것을 찾아 왔습니다. 바이너리나 텍스트를 감지하기 위해 표준 라이브러리에서 제공하는 포괄적인 솔루션입니다.사람들이 제안한 옵션을 검토한 결과 nix file 명령어가 최선의 선택인 것 같습니다(linux boxen용으로만 개발 중입니다).몇몇 다른 사람들은 파일을 이용한 해결책을 게시했지만, 제 생각에 그것들은 불필요하게 복잡합니다. 그래서 제가 생각해낸 것은 다음과 같습니다.

def test_file_isbinary(filename):
    cmd = shlex.split("file -b -e soft '{}'".format(filename))
    if subprocess.check_output(cmd)[:4] in {'ASCI', 'UTF-'}:
        return False
    return True

말할 필요도 없지만, 이 함수를 호출하는 코드는 파일을 테스트하기 전에 파일을 읽을 수 있는지 확인해야 합니다. 그렇지 않으면 파일이 바이너리로 잘못 인식됩니다.

나는 guess_type 함수를 사용하는 것이 가장 좋은 해결책이라고 생각합니다.여러 개의 밈 유형이 포함된 목록을 보유하고 있으며, 자신의 유형을 포함할 수도 있습니다.제가 문제를 해결하기 위해 한 스크립트가 여기 있습니다.

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는 경로 변수에 있는 디렉터리에 있는 모든 텍스트 파일이 있는 목록 개체를 반환합니다.

*NIX:

액세스 권한이 있는 경우fileshell-command, 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-loop에 삽입하여 현재 dir의 모든 파일에 대한 출력을 얻을 수도 있습니다.

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()))

모든 기본적인 방법들은 바이너리든 아니든 파이썬 라이브러리에 통합되었습니다.핍과 함께 설치합니다.

설명서에서:

>>> from binaryornot.check import is_binary
>>> is_binary('README.rst')
False

유닉스를 사용하고 계십니까? 그렇다면 다음을 시도해 보십시오.

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

셸 반환 값은 반전됩니다(0은 괜찮으므로 "text"를 찾으면 0을 반환하고 Python에서는 False 식입니다).

파일이 NULL 문자로 구성되어 있는지 확인하는 것이 더 간단한 방법입니다(\x00)을 사용하여in연산자, 예:

b'\x00' in open("foo.bar", 'rb').read()

전체 예시 아래를 참조하십시오.

#!/usr/bin/env python3
import argparse
if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('file', nargs=1)
    args = parser.parse_args()
    with open(args.file[0], 'rb') as f:
        if b'\x00' in f.read():
            print('The file is binary!')
        else:
            print('The file is not binary!')

샘플 사용량:

$ ./is_binary.py /etc/hosts
The file is not binary!
$ ./is_binary.py `which which`
The file is binary!

언급URL : https://stackoverflow.com/questions/898669/how-can-i-detect-if-a-file-is-binary-non-text-in-python

반응형