Como verificar o tipo de arquivos sem extensões em python?

87

Tenho uma pasta cheia de arquivos e eles não têm extensão. Como posso verificar os tipos de arquivo? Desejo verificar o tipo de arquivo e alterá-lo de acordo. Vamos supor que uma função filetype(x)retorne um tipo de arquivo como png. Eu quero fazer isso:

files = os.listdir(".")
for f in files:
    os.rename(f, f+filetype(f))

Como eu faço isso?

emnoor
fonte
Você terá que ser mais específico em relação a file types. Você quer dizer determinar se é um gif, png, bmp ou jpg? Quer apenas saber se é texto / binário? Executável?
JoeFish
@ thg435, uma vez que você tenha o tipo MIME, há uma maneira de convertê-lo em uma extensão de nome de arquivo adequada?
Mark Ransom
@Mark: sim, use guess_extension , mas na verdade, mimetypes não funcionam aqui, porque é baseado em extensões de arquivo. O que eles precisam é de libmagic (veja a 2ª resposta no link).
georg
1
tente este pypi.org/project/filetype ?
zx1986

Respostas:

89

Existem bibliotecas Python que podem reconhecer arquivos com base em seu conteúdo (geralmente um cabeçalho / número mágico) e que não dependem do nome ou extensão do arquivo.

Se estiver lidando com muitos tipos de arquivos diferentes, você pode usar python-magic. Isso é apenas uma ligação Python para a magicbiblioteca bem estabelecida . Isso tem uma boa reputação e (pequeno endosso) no uso limitado que fiz dele, tem sido sólido.

Também existem bibliotecas para tipos de arquivos mais especializados. Por exemplo, a biblioteca padrão do Python possui o imghdrmódulo que faz a mesma coisa apenas para tipos de arquivo de imagem.

Se você precisar de verificação de tipo de arquivo livre de dependência (Python puro), consulte filetype.

Chris Johnson
fonte
2
O pacote python-magic-win64funcionou para mim no Windows
ChesuCR
2
imghdr com combinação de tipo de arquivo funcionou para mim no Windows
Hrushikesh Dhumal
61

A biblioteca Python Magic fornece a funcionalidade de que você precisa.

Você pode instalar a biblioteca pip install python-magice usá-la da seguinte maneira:

>>> import magic

>>> magic.from_file('iceland.jpg')
'JPEG image data, JFIF standard 1.01'

>>> magic.from_file('iceland.jpg', mime=True)
'image/jpeg'

>>> magic.from_file('greenland.png')
'PNG image data, 600 x 1000, 8-bit colormap, non-interlaced'

>>> magic.from_file('greenland.png', mime=True)
'image/png'

O código Python, neste caso, está chamando libmagic por baixo do capô, que é a mesma biblioteca usada pelo filecomando * NIX . Portanto, isso faz a mesma coisa que as respostas baseadas em subprocesso / shell, mas sem essa sobrecarga.

Richard
fonte
6
Esteja ciente de que o pacote debian / ubuntu chamado python-magic é diferente do pacote pip de mesmo nome. Ambos são, import magicmas têm conteúdos incompatíveis. Consulte stackoverflow.com/a/16203777/3189 para obter mais informações.
Hamish Downer
1
@Richard Você se importa em elaborar sobre o aspecto geral? O que torna a python-magicbiblioteca mais eficiente do que usar abordagens de subprocesso?
Greg
9

No Unix e no Linux, existe o filecomando para adivinhar os tipos de arquivo. Há até uma porta do Windows .

Na página de manual :

O arquivo testa cada argumento na tentativa de classificá-lo. Existem três conjuntos de testes, executados nesta ordem: testes de sistema de arquivos, testes de número mágico e testes de idioma. O primeiro teste bem-sucedido faz com que o tipo de arquivo seja impresso.

Você precisaria executar o filecomando com o subprocessmódulo e, em seguida, analisar os resultados para descobrir uma extensão.

editar: Ignore minha resposta. Use a resposta de Chris Johnson .

Steven Rumbalski
fonte
1 Eu não sabia fileque fiz muito. # file arc.gif arc.gif: GIF image data, version 89a, 234 x 269
JoeFish
Bem, eu esperava que alguém tivesse uma resposta melhor. Ainda há muito trabalho para o OP, não é uma simples chamada de função.
Steven Rumbalski
2
+1 Um benefício de usar o filecomando é que ele é nativo na (maioria?) Distribuições Linux, enquanto o python-magicnão é e deve ser baixado e instalado antes de ser usado. Isso é um tanto problemático se o script que usa o módulo for portátil.
HelloGoodbye
7

No caso de imagens, você pode usar o imghdrmódulo.

>>> import imghdr
>>> imghdr.what('8e5d7e9d873e2a9db0e31f9dfc11cf47')  # You can pass a file name or a file object as first param. See doc for optional 2nd param.
'png'

Python 2 imghdr doc
Python 3 imghdr doc

Lewis Diamond
fonte
6

Você também pode instalar a fileligação oficial para Python, uma biblioteca chamada file-magic(ela não usa ctypes, como python-magic).

Ele está disponível no PyPI como arquivo mágico e no Debian como python-mágico . Para mim, esta biblioteca é a melhor para usar, pois está disponível no PyPI e no Debian (e provavelmente em outras distribuições), tornando o processo de implantação do seu software mais fácil. Também fiz um blog sobre como usá-lo .

Álvaro Justen
fonte
6
import subprocess
p = sub.Popen('file yourfile.txt', stdout=sub.PIPE, stderr=sub.PIPE)
output, errors = p.communicate()
print(output)

Como Steven apontou, subprocessé o caminho. Você pode obter a saída do comando acima como este post disse

xvatar
fonte
E como você captura a saída?
Mark Ransom
@MarkRansom, desculpe, não foi uma boa maneira, por favor, veja minhas atualizações acima
xvatar
Se você precisa interagir com seu sistema em vez de usar uma biblioteca Python, a solução é subótima na maioria das vezes, porque provavelmente não é útil em outros sistemas operacionais com uma API diferente.
erikbwork
4

Com a biblioteca de subprocesso mais recente, agora você pode usar o seguinte código (solução apenas * nix):

import subprocess
import shlex

filename = 'your_file'
cmd = shlex.split('file --mime-type {0}'.format(filename))
result = subprocess.check_output(cmd)
mime_type = result.split()[-1]
print mime_type
Berniey
fonte
Obrigado pela resposta. BTW, você não deve usar str.split () em uma linha cmd. use shlex.split (cmd) insteed.
emnoor
Em vez de usar shlex.split, por que não apenas correr subprocess.check_output(['file', '--mime-type', filename])?
Flimm
1

também você pode usar este código (python puro por 3 bytes de arquivo de cabeçalho):

full_path = os.path.join(MEDIA_ROOT, pathfile)

try:
    image_data = open(full_path, "rb").read()
except IOError:
    return "Incorrect Request :( !!!"

header_byte = image_data[0:3].encode("hex").lower()

if header_byte == '474946':
    return "image/gif"
elif header_byte == '89504e':
    return "image/png"
elif header_byte == 'ffd8ff':
    return "image/jpeg"
else:
    return "binary file"

sem qualquer pacote de instalação [e versão de atualização]

perene
fonte
Como posso verificar se há xlsx?
Harsha Biyani
Você pode usar por 4 ou 8 bytes. XLSX (Documento de formato MS Office Open XML) => 50 4B 03 04 (4 Bytes) => ASCII (PK ••) ou XLSX (documentos do MS Office 2007) => 50 4B 03 04 14 00 06 00 (8 Bytes) = > ASCII (PK ••••••)
evergreen
0

Só funciona para Linux, mas usando o módulo "sh" python você pode simplesmente chamar qualquer comando shell

https://pypi.org/project/sh/

pip instalar sh

importar sh

sh.file ("/ root / arquivo")

Saída: / root / arquivo: texto ASCII

Lelouch
fonte