2009-03-07 12 views

Odpowiedz

16

Nie ma gwarantowany sposób, ale tutaj jest kilka możliwości:

1) Spójrz na nagłówku pliku. Niestety, nagłówki są specyficzne dla plików, więc możesz być pewien, że jest to plik RAR, ale nie uzyskasz bardziej ogólnej odpowiedzi na pytanie, czy jest to tekst czy plik binarny.

2) Policz liczbę postaci, a nie postaci. Pliki tekstowe będą w większości alfabetyczne, podczas gdy pliki binarne - zwłaszcza skompresowane, takie jak rar, zip i inne - będą miały bardziej równomiernie reprezentowane bajty.

3) Poszukaj regularnie powtarzającego się wzoru znaków nowej linii.

1

Możesz wypróbować narzędzie DROID.

3

Jeśli plik składa się z bajtów 0x09 (TAB), 0x0A (line feed), 0x0C (form feed), 0x0D (powrót karetki) lub 0x20 przez 0x7E, to chyba tekst ASCII .

Jeśli plik zawiera jakikolwiek inny znak kontrolny ASCII, od 0x00 do 0x1F z wyłączeniem powyższych trzech, to prawdopodobnie są to dane binarne.

Tekst UTF-8 podąża za bardzo konkretnym wzorcem dla dowolnych bajtów z bitem wyższego rzędu, ale kodowania o stałej długości jak ISO-8859-1 nie. UTF-16 może często zawierać bajt zerowy (0x00), ale tylko w każdej innej pozycji.

Potrzebowałbyś słabszej heurystyki do czegokolwiek innego.

9

Zobacz bibliotekę JMimeMagic.

jMimeMagic jest biblioteka Java dla określania typu MIME plików lub strumieni.

+0

Interesująca biblioteka, ale w jaki sposób to pomoże? Informuje o typie mime, ale nie o tym, czy jest to plik binarny czy tekst. – Adam

+0

@Adam Nie rozumiem twojego pytania? Możesz sam wywnioskować z samego typu MIME, czy plik jest binarny czy nie, prawda? To znaczy. jeśli typ to "text/plain", powinien to być plik tekstowy. – dhiller

+0

OK, byłem tępy. Chodzi mi o to, że nadal trzeba napisać dodatkową logikę, aby interpretować typ MIME jako binarny lub tekstowy. "text/plain" nie jest jedynym opartym na tekście typem MIME. – Adam

3

Po prostu, aby poinformować, wybrałem zupełnie inną drogę. W moim przypadku są tylko 2 typy plików, szanse, że dany plik będzie binarny, są wysokie. Więc

  1. przypuszczać, że plik jest binarny, spróbuj robić to, co miało być wykonane (np Cofnięcie)
  2. catch wyjątek
  3. plik traktować jako tekstowych
  4. jeśli to się nie uda, coś jest nie tak z samego pliku
+0

Myślę, że to najlepsze podejście. Czy naprawdę obchodzi Cię, jaki jest typ pliku? Czy troszczysz się, czy możesz z tym zrobić pewne rzeczy. W wielu przypadkach, jeśli możesz zrobić te rzeczy, nie musisz wiedzieć, jaki jest typ. – stackexchanger

10

Uruchom file -bi {filename}. Jeśli cokolwiek zwróci, zaczyna się od "text /", to jest ono nie binarne, inaczej jest. ;-)

+1

Wygląda na to, że istnieją również "application/javascript" i "application/xml". Patrząc tutaj http://en.wikipedia.org/wiki/Internet_media_type sugeruje, że to nie jest takie proste. – Aaron

+1

Możesz sprawdzić za pomocą 'file -i {filename}' i sprawdzić, czy nie jest to 'charset = binary'. –

+0

Muszę powiedzieć, że nie byłem całkowicie poważny, gdy odpowiedziałem na powyższe. Pliki tekstowe są po prostu plikami binarnymi interpretowanymi w określony sposób. Jeśli miałeś na myśli, jeśli coś jest US-ASCII, możesz sprawdzić każdy bajt i sprawdzić, czy pasuje on do twojej definicji tekstu. Ale może miałeś na myśli * dowolny * typ kodowania znaków. To będzie znacznie trudniejsze. Zwłaszcza jeśli bierzesz pod uwagę te, które używają kodowania opartego na entropii (postacie występujące często wymagają mniejszej ilości bitów). Z drugiej strony, jeśli miałbyś na myśli wszystko w US-ASCII, to kodowany obraz Base64 byłby również tekstem? –

5

Użyłem tego kodu i działa dla języka angielskiego i niemieckiego tekstu całkiem dobrze:

private boolean isTextFile(String filePath) throws Exception { 
    File f = new File(filePath); 
    if(!f.exists()) 
     return false; 
    FileInputStream in = new FileInputStream(f); 
    int size = in.available(); 
    if(size > 1000) 
     size = 1000; 
    byte[] data = new byte[size]; 
    in.read(data); 
    in.close(); 
    String s = new String(data, "ISO-8859-1"); 
    String s2 = s.replaceAll(
      "[a-zA-Z0-9ßöäü\\.\\*!\"§\\$\\%&/()=\\[email protected]~'#:,;\\"+ 
      "+><\\|\\[\\]\\{\\}\\^°²³\\\\ \\n\\r\\t_\\-`´âêîô"+ 
      "ÂÊÔÎáéíóàèìòÁÉÍÓÀÈÌÒ©‰¢£¥€±¿»«¼½¾™ª]", ""); 
    // will delete all text signs 

    double d = (double)(s.length() - s2.length())/(double)(s.length()); 
    // percentage of text signs in the text 
    return d > 0.95; 
} 
+2

Pomysł jest interesujący, ale zamiast replaceAll, który niepotrzebnie tworzy nowy ciąg, po prostu użyłbym pętli for do zliczania tekstu i znaków nietekstowych. Ustawienie limitu na 1000 znaków oznacza, że ​​nie będzie to * zbyt * kosztowne, ale nadal jest to bezużyteczny koszt. – miniBill

8

zrobiłem tego. Trochę prostsze, ale dla języków łacińskich, powinno działać dobrze, z regulacją współczynnika.

/** 
* Guess whether given file is binary. Just checks for anything under 0x09. 
*/ 
public static boolean isBinaryFile(File f) throws FileNotFoundException, IOException { 
    FileInputStream in = new FileInputStream(f); 
    int size = in.available(); 
    if(size > 1024) size = 1024; 
    byte[] data = new byte[size]; 
    in.read(data); 
    in.close(); 

    int ascii = 0; 
    int other = 0; 

    for(int i = 0; i < data.length; i++) { 
     byte b = data[i]; 
     if(b < 0x09) return true; 

     if(b == 0x09 || b == 0x0A || b == 0x0C || b == 0x0D) ascii++; 
     else if(b >= 0x20 && b <= 0x7E) ascii++; 
     else other++; 
    } 

    if(other == 0) return false; 

    return 100 * other/(ascii + other) > 95; 
} 
+1

Dzięki za tę funkcję. Jedną rzeczą, z którą mam problem jest dowiedzieć się, co się dzieje z wartością zwracaną: 'return (ascii + inne) * 100/other> 95;' Który, o ile czegoś nie brakuje, zawsze zwróci true: Głównie, rozmiar będzie wynosił '1024', podobnie jak" data.length ", a zatem' (ascii + inne) '. Więc jeśli '(ascii + inne) * 100 == 102400' to' 102400/inne> 95' => '102400> 95 * inne' => inne <1078' Co oznacza, że ​​musi być więcej niż 1078 (z 1024) "inne" do tego, aby zwrócić fałszywe, oczywiście niemożliwe. Czy miałeś na myśli ?: '(other/size * 100> 95)' A może czegoś brakuje? – Inversus

+0

Myślę, że masz rację. Naprawiono kod. –

+0

Fajne fajne. Tak, też to zrobiłem. Jeszcze raz dziękuję :) – Inversus

5

Korzystanie Java 7 klasa plików http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#probeContentType(java.nio.file.Path)

boolean isBinaryFile(File f) throws IOException { 
     String type = Files.probeContentType(f.toPath()); 
     if (type == null) { 
      //type couldn't be determined, assume binary 
      return true; 
     } else if (type.startsWith("text")) { 
      return false; 
     } else { 
      //type isn't text 
      return true; 
     } 
    } 
+3

To tylko sprawdza rozszerzenie pliku, a nie zawartość pliku, a tym samym bezużyteczne. – ares

+1

To zależy od tego, co jest zainstalowane, zgodnie z dokumentami. – Adam