Como posso saber se um arquivo é binário (não texto) em python?
Estou pesquisando um grande conjunto de arquivos em python e continuo obtendo correspondências em arquivos binários. Isso faz com que a saída pareça incrivelmente confusa.
Eu sei que poderia usar grep -I
, mas estou fazendo mais com os dados do que o grep permite.
No passado, eu teria apenas procurado por caracteres maiores do que 0x7f
, mas utf8
e assim por diante, tornam isso impossível em sistemas modernos. Idealmente, a solução seria rápida, mas qualquer solução serve.
grep
se utiliza para identificar arquivos binários é semelhante à postada por Jorge Orpinel abaixo . A menos que você defina a-z
opção, ele irá apenas procurar um caractere nulo ("\000"
) no arquivo. Com-z
, ele procura"\200"
. Os interessados e / ou céticos podem verificar a linha 1126 degrep.c
. Não consegui encontrar uma página da web com o código-fonte, mas é claro que você pode obtê-la em gnu.org ou em uma distro .git diff
e o GNUdiff
também usam a mesma estratégia. Não tenho certeza se é tão predominante porque é muito mais rápido e fácil do que a alternativa, ou se é apenas por causa da relativa raridade de arquivos UTF-16 em sistemas que tendem a ter esses utilitários instalados.Respostas:
Você também pode usar o módulo mimetypes :
É bastante fácil compilar uma lista de tipos MIME binários. Por exemplo, o Apache distribui com um arquivo mime.types que você pode analisar em um conjunto de listas, binários e texto e, em seguida, verificar se o mime está em sua lista de texto ou binária.
fonte
mimetypes
a usar o conteúdo de um arquivo em vez de apenas seu nome?file
relata como "texto Unicode UTF-8, com linhas muito longas", mas mimetypes.gest_type () retornará (nenhum, nenhum). Além disso, a lista de tipos MIME do Apache é uma lista de permissões / subconjunto. Não é de forma alguma uma lista completa de tipos MIME. Não pode ser usado para classificar todos os arquivos como texto ou não texto.Ainda outro método baseado no comportamento do arquivo (1) :
Exemplo:
fonte
bytearray([7,8,9,10,12,13,27]) + bytearray(range(0x20, 0x7f)) + bytearray(range(0x80, 0x100))
. Consulte Python, arquivo (1) - Por que os números [7,8,9,10,12,13,27] e o intervalo (0x20, 0x100) são usados para determinar texto x arquivo binário e github.com/file/file/ blob /…0x7f
(DEL
).11
ouVT
? Na tabela 11 é considerado texto ASCII simples, e este é overtical tab
.Se você estiver usando python3 com utf-8, é simples, basta abrir o arquivo no modo de texto e parar o processamento se obtiver um
UnicodeDecodeError
. Python3 usará unicode ao lidar com arquivos em modo texto (e bytearray em modo binário) - se sua codificação não puder decodificar arquivos arbitrários, é bem provável que você os obtenhaUnicodeDecodeError
.Exemplo:
fonte
with open(filename, 'r', encoding='utf-8') as f
diretamente?Se ajudar, muitos tipos binários começam com números mágicos. Aqui está uma lista de assinaturas de arquivo.
fonte
Experimente isto:
fonte
git diff
na verdade funciona dessa maneira e, com certeza, detecta arquivos UTF-16 como binários.diff
também funciona dessa maneira. Ele tem problemas semelhantes com arquivos UTF-16.file
detecta corretamente os mesmos arquivos de texto UTF-16. Não verifiquei ogrep
código de, mas ele também detecta arquivos UTF-16 como binários.file(1)
que não é seguro imprimir sem conversão, portanto, este método é apropriado neste caso.Aqui está uma sugestão que usa o comando de arquivo Unix :
Exemplo de uso:
Ele tem o lado ruim de não ser portátil para o Windows (a menos que você tenha algo como o
file
comando lá) e ter que gerar um processo externo para cada arquivo, que pode não ser palatável.fonte
file
como "Configuração congelada do Sendmail - versão m" - observe a ausência da string "texto". Talvez usefile -i
?Use a biblioteca binaryornot ( GitHub ).
É muito simples e baseado no código encontrado nesta questão stackoverflow.
Você pode realmente escrever isso em 2 linhas de código, no entanto, este pacote evita que você tenha que escrever e testar completamente essas 2 linhas de código com todos os tipos de arquivos estranhos, multiplataforma.
fonte
Normalmente você tem que adivinhar.
Você pode ver as extensões como uma pista, se os arquivos as tiverem.
Você também pode reconhecer formatos binários conhecidos e ignorá-los.
Caso contrário, veja que proporção de bytes ASCII não imprimíveis você tem e faça uma estimativa a partir disso.
Você também pode tentar decodificar de UTF-8 e ver se isso produz uma saída razoável.
fonte
Uma solução mais curta, com um aviso UTF-16:
fonte
for line in file
pode consumir uma quantidade ilimitada de memória atéb'\n'
ser encontrado".read()"
retorna uma cadeia de bytes aqui que é iterável (produz bytes individuais).Podemos usar o próprio python para verificar se um arquivo é binário, porque ele falha se tentarmos abrir o arquivo binário em modo de texto
fonte
Se você não estiver no Windows, pode usar o Python Magic para determinar o tipo de arquivo. Em seguida, você pode verificar se é um tipo de texto / mime.
fonte
Aqui está uma função que primeiro verifica se o arquivo começa com um BOM e, se não, procura um byte zero dentro dos 8192 bytes iniciais:
Tecnicamente, a verificação do BOM UTF-8 é desnecessária porque ele não deve conter bytes zero para todos os fins práticos. Mas como é uma codificação muito comum, é mais rápido verificar o BOM no início em vez de verificar todos os 8192 bytes em busca de 0.
fonte
Tente usar a python-magic mantida atualmente, que não é o mesmo módulo na resposta de @Kami Kisiel. Isso oferece suporte a todas as plataformas, incluindo Windows, no entanto, você precisará dos
libmagic
arquivos binários. Isso é explicado no README.Ao contrário do módulo mimetypes , ele não usa a extensão do arquivo e, em vez disso, inspeciona o conteúdo do arquivo.
fonte
Vim aqui procurando exatamente a mesma coisa - uma solução abrangente fornecida pela biblioteca padrão para detectar binário ou texto. Depois de revisar as opções que as pessoas sugeriram, o comando nix file parece ser a melhor escolha (estou desenvolvendo apenas para linux boxen). Alguns outros postaram soluções usando o arquivo, mas elas são desnecessariamente complicadas na minha opinião, então aqui está o que eu descobri:
Não é preciso dizer, mas o código que chama esta função deve garantir que você possa ler um arquivo antes de testá-lo, caso contrário, ele será detectado por engano como binário.
fonte
Eu acho que a melhor solução é usar a função guess_type. Ele contém uma lista com vários tipos MIME e você também pode incluir seus próprios tipos. Aí vem o script que fiz para resolver meu problema:
Ele está dentro de uma classe, como você pode ver com base na estrutura de uso do código. Mas você pode alterar muito as coisas que deseja implementar em seu aplicativo. É muito simples de usar. O método getTextFiles retorna um objeto de lista com todos os arquivos de texto que residem no diretório que você passa na variável de caminho.
fonte
em * NIX:
Se você tiver acesso ao
file
comando shell, shlex pode ajudar a tornar o módulo de subprocesso mais utilizável:Ou você também pode inserir isso em um loop for para obter a saída de todos os arquivos no diretório atual usando:
ou para todos os subdiretórios:
fonte
A maioria dos programas considera o arquivo binário (que é qualquer arquivo que não seja "orientado por linha") se contiver um caractere NULL .
Aqui está a versão de perl de
pp_fttext()
(pp_sys.c
) implementada em Python:Fonte: "adivinhe se o arquivo é texto ou binário" do Perl implementado em Python
fonte
você está no unix? se sim, tente:
Os valores de retorno do shell são invertidos (0 está certo, portanto, se encontrar "texto", ele retornará 0, e em Python essa é uma expressão falsa).
fonte
file
com o-b
switch; ele imprimirá apenas o tipo de arquivo sem o caminho.is_binary_file = lambda filename: "text" in subprocess.check_output(["file", "-b", filename])
A maneira mais simples é verificar se o arquivo consiste no caractere NULL (
\x00
) usando oin
operador, por exemplo:Veja abaixo o exemplo completo:
Uso de amostra:
fonte
Documentação
fonte