Jak mogę sprawdzić, czy plik jest binarny (nietekstowy) w Pythonie?
Przeszukuję duży zestaw plików w Pythonie i ciągle otrzymuję dopasowania w plikach binarnych. To sprawia, że wydruk wygląda niesamowicie niechlujnie.
Wiem, że mógłbym użyć grep -I
, ale robię więcej z danymi, niż pozwala na to grep.
W przeszłości szukałbym po prostu znaków większych niż 0x7f
, ale utf8
i tym podobnych, uniemożliwiających to w nowoczesnych systemach. Idealnie rozwiązanie byłoby szybkie, ale każde rozwiązanie wystarczy.
grep
używa się do identyfikacji plików binarnych, jest podobna do tej opublikowanej przez Jorge Orpinela poniżej . O ile nie ustawisz tej-z
opcji, po prostu skanuje w poszukiwaniu znaku null ("\000"
) w pliku. Dzięki-z
temu skanuje w poszukiwaniu plików"\200"
. Zainteresowani i / lub sceptyczni mogą sprawdzić linię 1126 ofgrep.c
. Przepraszamy, nie mogłem znaleźć strony internetowej z kodem źródłowym, ale oczywiście możesz ją pobrać z gnu.org lub za pośrednictwem dystrybucji .git diff
i GNUdiff
również używają tej samej strategii. Nie jestem pewien, czy jest tak powszechny, ponieważ jest o wiele szybszy i łatwiejszy niż alternatywa, czy też jest to spowodowane względną rzadkością plików UTF-16 w systemach, które mają zwykle zainstalowane te narzędzia.Odpowiedzi:
Możesz także skorzystać z modułu MIME :
Utworzenie listy binarnych typów MIME jest dość łatwe. Na przykład Apache dystrybuuje plik mime.types, który można przeanalizować w zestaw list, plików binarnych i tekstowych, a następnie sprawdzić, czy mime znajduje się na liście tekstowej lub binarnej.
źródło
mimetypes
użyć zawartości pliku, a nie tylko jego nazwy?file
zgłasza jako „tekst UTF-8 Unicode, z bardzo długimi liniami”, ale zwróci mimetypes.gest_type () (Brak, Brak). Ponadto lista typów MIME Apache jest białą listą / podzbiorem. Nie jest to bynajmniej pełna lista typów MIME. Nie można go użyć do sklasyfikowania wszystkich plików jako tekstowych lub nietekstowych.Jeszcze inna metoda oparta na zachowaniu file (1) :
Przykład:
źródło
bytearray([7,8,9,10,12,13,27]) + bytearray(range(0x20, 0x7f)) + bytearray(range(0x80, 0x100))
zamiast niego. Zobacz Python, plik (1) - Dlaczego liczby [7,8,9,10,12,13,27] i zakres (0x20, 0x100) są używane do określania tekstu względem pliku binarnego i github.com/file/file/ blob /…0x7f
(DEL
).11
lubVT
? W tabeli 11 jest uważany za zwykły tekst ASCII, a to jestvertical tab
.Jeśli używasz python3 z utf-8, jest to proste, po prostu otwórz plik w trybie tekstowym i zatrzymaj przetwarzanie, jeśli pojawi się plik
UnicodeDecodeError
. Python3 użyje Unicode podczas obsługi plików w trybie tekstowym (i bytearray w trybie binarnym) - jeśli twoje kodowanie nie może zdekodować dowolnych plików, jest całkiem prawdopodobne, że otrzymaszUnicodeDecodeError
.Przykład:
źródło
with open(filename, 'r', encoding='utf-8') as f
bezpośrednio?Jeśli to pomoże, wiele typów binarnych zaczyna się od magicznych liczb. Oto lista podpisów plików.
źródło
Spróbuj tego:
źródło
git diff
faktycznie działa w ten sposób i na pewno wykrywa pliki UTF-16 jako binarne.diff
też działa w ten sposób. Ma podobne problemy z plikami UTF-16.file
poprawnie wykrywa te same pliki, co tekst UTF-16. Nie pobrałemgrep
kodu, ale on również wykrywa pliki UTF-16 jako binarne.file(1)
którymi drukowanie bez konwersji nie jest bezpieczne, więc ta metoda jest odpowiednia w tym przypadku.Oto sugestia, która używa polecenia pliku systemu Unix :
Przykładowe użycie:
Ma wady polegające na tym, że nie jest przenośny do systemu Windows (chyba że masz tam coś takiego, jak
file
polecenie) i konieczność tworzenia zewnętrznego procesu dla każdego pliku, który może nie być przyjemny.źródło
file
jako „Zamrożona konfiguracja Sendmaila - wersja m” - zauważ brak ciągu znaków „tekst”. Może użyćfile -i
?Użyj biblioteki binaryornot ( GitHub ).
Jest to bardzo proste i oparte na kodzie znalezionym w tym pytaniu dotyczącym stackoverflow.
W rzeczywistości możesz napisać to w 2 wierszach kodu, jednak ten pakiet oszczędza ci konieczności pisania i dokładnego testowania tych 2 wierszy kodu z różnymi dziwnymi typami plików, na różnych platformach.
źródło
Zwykle musisz zgadywać.
Możesz spojrzeć na rozszerzenia jako jedną wskazówkę, jeśli pliki je mają.
Możesz także rozpoznać znane formaty binarne i zignorować je.
W przeciwnym razie zobacz, jaki procent posiadasz niedrukowalnych bajtów ASCII i zgadnij z tego.
Możesz także spróbować dekodować z UTF-8 i sprawdzić, czy daje to rozsądny wynik.
źródło
Krótsze rozwiązanie z ostrzeżeniem UTF-16:
źródło
for line in file
może zużywać nieograniczoną ilość pamięci, dopóki nieb'\n'
zostanie znaleziony".read()"
zwraca tutaj bytestring, który jest iterowalny (daje pojedyncze bajty).Możemy użyć samego Pythona, aby sprawdzić, czy plik jest binarny, ponieważ nie powiedzie się, jeśli spróbujemy otworzyć plik binarny w trybie tekstowym
źródło
Jeśli nie korzystasz z systemu Windows, możesz użyć Python Magic do określenia typu pliku. Następnie możesz sprawdzić, czy jest to typ tekstowy / mime.
źródło
Oto funkcja, która najpierw sprawdza, czy plik zaczyna się od BOM, a jeśli nie, szuka bajtu zerowego w początkowych 8192 bajtach:
Z technicznego punktu widzenia sprawdzenie BOM UTF-8 jest niepotrzebne, ponieważ nie powinno zawierać zerowych bajtów ze wszystkich praktycznych powodów. Ale ponieważ jest to bardzo powszechne kodowanie, szybciej jest sprawdzić BOM na początku, zamiast skanować wszystkie 8192 bajty w poszukiwaniu 0.
źródło
Spróbuj użyć aktualnie utrzymywanej magii Pythona, która nie jest tym samym modułem w odpowiedzi @Kami Kisiel. Obsługuje to wszystkie platformy, w tym Windows, jednak będziesz potrzebować
libmagic
plików binarnych. Jest to wyjaśnione w README.W przeciwieństwie do modułu mimetypes , nie używa rozszerzenia pliku i zamiast tego sprawdza zawartość pliku.
źródło
Przyjechałem tutaj, szukając dokładnie tego samego - kompleksowego rozwiązania dostarczanego przez bibliotekę standardową do wykrywania plików binarnych lub tekstowych. Po przejrzeniu opcji sugerowanych przez ludzi, polecenie nix file wydaje się być najlepszym wyborem (rozwijam się tylko dla linux boxen). Niektórzy inni opublikowali rozwiązania wykorzystujące plik, ale moim zdaniem są one niepotrzebnie skomplikowane, więc oto co wymyśliłem:
Powinno być oczywiste, ale Twój kod, który wywołuje tę funkcję, powinien upewnić się, że możesz odczytać plik przed jego przetestowaniem, w przeciwnym razie zostanie to omyłkowo wykryte jako binarny.
źródło
Myślę, że najlepszym rozwiązaniem jest użycie funkcji guess_type. Zawiera listę z kilkoma typami MIME, a także możesz dołączyć własne typy. Oto skrypt, który zrobiłem, aby rozwiązać mój problem:
Znajduje się wewnątrz klasy, jak widać na podstawie struktury kodu. Ale możesz prawie zmienić rzeczy, które chcesz zaimplementować w swojej aplikacji. Jest dość prosty w użyciu. Metoda getTextFiles zwraca obiekt listy ze wszystkimi plikami tekstowymi, które znajdują się w katalogu, który przekazujesz w zmiennej path.
źródło
na * NIX:
Jeśli masz dostęp do polecenia
file
powłoki, shlex może pomóc uczynić moduł podprocesu bardziej użytecznym:Możesz też umieścić to w pętli for, aby uzyskać dane wyjściowe dla wszystkich plików w bieżącym katalogu, używając:
lub dla wszystkich podkatalogów:
źródło
Większość programów uważa, że plik jest binarny (czyli każdy plik, który nie jest „zorientowany liniowo”), jeśli zawiera znak NULL .
Oto wersja perla
pp_fttext()
(pp_sys.c
) zaimplementowana w Pythonie:Źródło: Perl „Zgadnij, czy plik jest tekstowy czy binarny” zaimplementowany w Pythonie
źródło
jesteś w unixie? jeśli tak, spróbuj:
Wartości zwracane przez powłokę są odwracane (0 jest w porządku, więc jeśli znajdzie "tekst", zwróci 0, aw Pythonie jest to fałszywe wyrażenie).
źródło
file
z-b
przełącznikiem; wypisze tylko typ pliku bez ścieżki.is_binary_file = lambda filename: "text" in subprocess.check_output(["file", "-b", filename])
Prostszym sposobem jest sprawdzenie, czy plik zawiera znak NULL (
\x00
) za pomocąin
operatora, na przykład:Zobacz poniżej pełny przykład:
Przykładowe użycie:
źródło
Dokumentacja
źródło