Jak sprawdzić typ plików bez rozszerzeń w Pythonie?

87

Mam folder pełen plików i nie mają one rozszerzenia. Jak mogę sprawdzić typy plików? Chcę sprawdzić typ pliku i odpowiednio zmienić nazwę pliku. Załóżmy, że funkcja filetype(x)zwraca typ pliku, taki jak png. Chce to zrobić:

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

Jak mam to zrobic?

emnoor
źródło
Będziesz musiał być bardziej szczegółowy w odniesieniu do file types. Masz na myśli określenie, czy jest to gif, png, bmp czy jpg? Czy chcesz tylko wiedzieć, czy jest to tekst / plik binarny? Wykonywalne?
JoeFish
@ thg435, czy gdy masz już typ MIME, jest sposób na przekonwertowanie go na odpowiednie rozszerzenie nazwy pliku?
Mark Ransom
@Mark: tak, użyj guess_extension , ale w rzeczywistości typy MIME nie będą tutaj działać, ponieważ są oparte na rozszerzeniach plików. Potrzebują libmagic (patrz druga odpowiedź w linku).
georg
1
spróbuj tego pypi.org/project/filetype ?
zx1986

Odpowiedzi:

92

Istnieją biblioteki Pythona, które potrafią rozpoznawać pliki na podstawie ich zawartości (zwykle nagłówek / numer magiczny) i które nie opierają się na nazwie ani rozszerzeniu pliku.

Jeśli adresujesz wiele różnych typów plików, możesz użyć python-magic. To tylko powiązanie Pythona z dobrze znaną magicbiblioteką. Ma dobrą reputację i (niewielka aprobata) w ograniczonym zakresie, w jakim go wykorzystałem, był solidny.

Istnieją również biblioteki dla bardziej wyspecjalizowanych typów plików. Na przykład standardowa biblioteka Pythona ma imghdrmoduł, który robi to samo tylko dla typów plików obrazów.

Jeśli potrzebujesz sprawdzania typu plików bez zależności (czysty Python), zobacz filetype.

Chris Johnson
źródło
2
Pakiet python-magic-win64działał dla mnie w systemie Windows
ChesuCR
2
imghdr z kombinacją typu pliku działał dla mnie w
systemie
62

Biblioteka Python Magic zapewnia potrzebną funkcjonalność.

Możesz zainstalować bibliotekę pip install python-magici używać jej w następujący sposób:

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

Kod Pythona w tym przypadku wywołuje libmagic pod maską, która jest tą samą biblioteką, której używa filepolecenie * NIX . Tak więc robi to to samo, co odpowiedzi oparte na podprocesie / powłoce, ale bez tego narzutu.

Richard
źródło
6
Uważaj, pakiet debian / ubuntu o nazwie python-magic różni się od pakietu pip o tej samej nazwie. Oba są, import magicale mają niezgodną zawartość. Więcej informacji znajdziesz na stackoverflow.com/a/16203777/3189 .
Hamish Downer
1
@Richard Czy nie masz nic przeciwko omówieniu ogólnego aspektu? Co sprawia, że python-magicbiblioteka jest bardziej wydajna niż stosowanie podejść podprocesowych?
Greg
9

W systemach Unix i Linux istnieje filepolecenie odgadywania typów plików. Jest nawet port Windows .

Od strony man :

Plik sprawdza każdy argument, próbując go sklasyfikować. Istnieją trzy zestawy testów, wykonywane w następującej kolejności: testy systemu plików, testy liczb magicznych i testy językowe. Pierwszy pomyślnie zakończony test powoduje wydrukowanie typu pliku.

Trzeba by uruchomić filepolecenie z subprocessmodułem, a następnie przeanalizować wyniki, aby znaleźć rozszerzenie.

edycja: Ignoruj ​​moją odpowiedź. Skorzystaj Chrisa Johnsona odpowiedź zamiast.

Steven Rumbalski
źródło
+1 Nie zdawałem sobie sprawy, fileże zrobiłem tyle. # file arc.gif arc.gif: GIF image data, version 89a, 234 x 269
JoeFish
Cóż, miałem nadzieję, że ktoś miał lepszą odpowiedź. W przypadku OP wciąż jest dużo pracy, nie jest to proste wywołanie funkcji.
Steven Rumbalski
2
+1 Jedną korzyścią z używania tego filepolecenia jest to, że jest natywna w (większości?) Dystrybucjach Linuksa, podczas gdy python-magicnie jest i musi zostać pobrana i zainstalowana przed użyciem. Jest to pewien problem, jeśli skrypt używający modułu ma być przenośny.
HelloGoodbye
7

W przypadku obrazów można skorzystać z imghdrmodułu.

>>> 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
źródło
6

Możesz także zainstalować oficjalne filepowiązanie dla Pythona, bibliotekę o nazwie file-magic(nie używa ctypów, takich jak python-magic).

Jest dostępny na PyPI jako magia plików, a na Debianie jako magia pythona . Dla mnie ta biblioteka jest najlepsza w użyciu, ponieważ jest dostępna na PyPI i na Debianie (i prawdopodobnie w innych dystrybucjach), ułatwiając proces wdrażania oprogramowania. Pisałem też na blogu o tym, jak go używać .

Álvaro Justen
źródło
6
import subprocess
p = sub.Popen('file yourfile.txt', stdout=sub.PIPE, stderr=sub.PIPE)
output, errors = p.communicate()
print(output)

Jak zauważył Steven, subprocessjest droga. Możesz uzyskać dane wyjściowe polecenia w powyższy sposób, jak powiedział ten post

xvatar
źródło
Jak uchwycić wynik?
Mark Ransom
@MarkRansom przepraszam, że to nie był dobry sposób, zobacz moje aktualizacje powyżej
xvatar
Jeśli zamiast korzystać z biblioteki Python, musisz wchodzić w interakcję ze swoim systemem, przez większość czasu rozwiązanie jest nieoptymalne, ponieważ prawdopodobnie nie będzie przydatne w innych systemach operacyjnych z innym interfejsem API.
erikbwork
4

Dzięki nowszej bibliotece podprocesów możesz teraz użyć następującego kodu (tylko rozwiązanie * 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
źródło
Dziękuję za odpowiedź. BTW, nie powinieneś używać str.split () w linii cmd. użyj insteed shlex.split (cmd).
emnoor
Zamiast używać shlex.split, dlaczego nie po prostu uruchomić subprocess.check_output(['file', '--mime-type', filename])?
Flimm
1

możesz również użyć tego kodu (czysty Python przez 3 bajty pliku nagłówkowego):

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"

bez instalacji pakietu [i aktualizacji wersji]

zimozielony
źródło
Jak mogę sprawdzić plik XLSX?
Harsha Biyani
Możesz użyć 4 lub 8 bajtów. XLSX (dokument w formacie MS Office Open XML) => 50 4B 03 04 (4 bajty) => ASCII (PK ••) lub XLSX (dokumenty MS Office 2007) => 50 4B 03 04 14 00 06 00 (8 bajtów) = > ASCII (PK ••••••)
wiecznie zielony
0

Działa tylko dla Linuksa, ale używając modułu Pythona "sh" możesz po prostu wywołać dowolne polecenie powłoki

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

pip install sh

import sh

sh.file („/ root / plik”)

Wyjście: / root / file: tekst ASCII

Lelouch
źródło