2009-09-18 11 views
13

Potrzebuję zidentyfikować, który plik plik jest tekst, który jest w katalogu.Jak rozpoznać pliki binarne i tekstowe za pomocą języka Python?

Próbowałem używać mimetypes, ale to nie jest dobry pomysł w moim przypadku, ponieważ nie można zidentyfikować wszystkich plików mimes, a ja mam tutaj nieznajomych ... Po prostu potrzebuję znać, binarny lub tekstowy. Prosty ? Ale nie mogłem znaleźć rozwiązanie ...

Dzięki

+2

Co to jest plik tekstowy? Czy na przykład kodowanie Unicode UTF-16-BE? –

+3

Musisz dokładnie określić, co rozumie się przez "binarny" i "tekst", zanim ktokolwiek może ci pomóc. –

+0

Plik tekstowy to dowolny plik, który może odczytać człowiek. Powiedz, każdy plik, który można odczytać za pomocą polecenia "cat" (linux) lub "type" (windows). – Thomas

Odpowiedz

9

Dzięki wszystkim znalazłem rozwiązanie, które pasowało do mojego problemu. Znalazłem ten kod pod numerem http://code.activestate.com/recipes/173220/ i zmieniłem tylko kawałek, który mi odpowiada.

Działa dobrze.

from __future__ import division 
import string 

def istext(filename): 
    s=open(filename).read(512) 
    text_characters = "".join(map(chr, range(32, 127)) + list("\n\r\t\b")) 
    _null_trans = string.maketrans("", "") 
    if not s: 
     # Empty files are considered text 
     return True 
    if "\0" in s: 
     # Files with null bytes are likely binary 
     return False 
    # Get the non-text characters (maps a character to itself then 
    # use the 'remove' option to get rid of the text characters.) 
    t = s.translate(_null_trans, text_characters) 
    # If more than 30% non-text characters, then 
    # this is considered a binary file 
    if float(len(t))/float(len(s)) > 0.30: 
     return False 
    return True 
+7

Mała korekta dla twojego kodu: 'jeśli float (len (t))/float (len (s))> 0.30: return 0'W przeciwnym razie python użyje dzielenia liczby całkowitej, a porównanie będzie prawdziwe kiedy len (t) == len (s) –

+1

Thomas, zastosuj tę korektę "pływaka" do odpowiedzi! Activestate powinien także naprawić swój przepis! ;) ale nie mogę się tym przejmować, żeby się tam znaleźć. –

+0

również jest końcowe * na ostatniej linii, nie powinno tam być –

4

Jeśli skrypt jest uruchomiony na * nix, można użyć mniej więcej tak:

import subprocess 
import re 

def is_text(fn): 
    msg = subprocess.Popen(["file", fn], stdout=subprocess.PIPE).communicate()[0] 
    return re.search('text', msg) != None 
+0

Nie ma potrzeby "ponownego", jeśli tylko szukanie podciągu. –

+0

Nie działa, jeśli 'tekst' jest częścią pliku plików binarnych. – Paddre

+1

Sugeruję Popen (["file", "--mime", fn]. ...). W przeciwnym razie słowo "tekst" może się nie pojawić. W moim systemie Linux odpowiedź na coś, co wygląda jak program Fortran, to "program FORTAN". Jeśli dodasz przełącznik mime, otrzymasz "text/x-fortran; charset = us-ascii". – Tsf

7

To naturalnie nie proste. Nie można się na pewno dowiedzieć, choć w większości przypadków można się domyślić.

Co może chcesz zrobić:

  • Look znanych magicznych liczb w podpisach binarnych
  • Look dla Unicode kolejności bajtów znak na początku pliku
  • Jeśli plik jest regularnie 00 xx 00 xx 00 xx (dla arbitralnego xx) lub odwrotnie, to całkiem możliwe, że UTF-16
  • W przeciwnym razie szukaj 0s w pliku; plik o wartości 0 jest mało prawdopodobny, ponieważ jest to plik tekstowy kodujący pojedynczy bajt.

Ale to wszystko heurystyczny - to całkiem możliwe, że plik, który jest ważny plik tekstowy i poprawny plik obrazu, na przykład. Byłoby to prawdopodobnie nonsensem w postaci pliku tekstowego, ale legalne w niektórych kodowaniu lub innych ...

4

To może być możliwe użycie libmagic odgadnąć typ MIME pliku przy użyciu python-magic. Jeśli odzyskasz coś w przestrzeni nazw "text/*", prawdopodobnie jest to plik tekstowy, podczas gdy cokolwiek innego prawdopodobnie jest to binary file.

Powiązane problemy