2009-03-07 8 views

ответ

16

Там нет гарантированного способа, но вот несколько возможностей:

1) Посмотрите на заголовок на файле. К сожалению, заголовки зависят от файлов, поэтому, хотя вы можете узнать, что это RAR-файл, вы не получите более общий ответ о том, является ли он текстовым или двоичным.

2) Подсчитайте количество символов и несимвольных типов. Текстовые файлы будут в основном алфавитными символами, в то время как двоичные файлы - особенно сжатые, такие как rar, zip и т. Д. - будут иметь тенденцию иметь более равномерно представленные байты.

3) Ищите регулярно повторяющийся узор новых строк.

1

Вы можете попробовать инструмент DROID.

3

Если файл состоит из (вкладки) байт 0x09, 0x0A (строки), 0x0C (форма подачи), 0x0D (возврат каретки) или 0x20 через 0x7E, то это, вероятно, ASCII текст ,

Если файл содержит любой другой управляющий символ ASCII, от 0x00 до 0x1F, исключая три выше, то это, вероятно, двоичные данные.

Текст UTF-8 следует очень специфичному шаблону для любых байтов с битом высокого порядка, но кодировки с фиксированной длиной, такие как ISO-8859-1, не имеют. UTF-16 часто может содержать нулевой байт (0x00), но только в любой другой позиции.

Вам понадобится более слабая эвристика для чего-либо еще.

9

Посмотрите на библиотеку JMimeMagic.

jMimeMagic библиотека Java для определения типа MIME файлов или потоков.

+0

Интересная библиотека, но как это поможет? Он сообщает вам тип mime, но не является ли он двоичным или текстовым. – Adam

+0

@Adam Я не понимаю ваш вопрос? Вы можете вывести из самого MIME-типа, является ли файл двоичным или нет, не так ли? То есть если тип «text/plain», это должен быть текстовый файл. – dhiller

+0

ОК, я был тупым. Я имел в виду, что вам все еще приходится писать дополнительную логику, чтобы интерпретировать тип mime как двоичный или текстовый. «text/plain» - не единственный текстовый тип mime. – Adam

3

Чтобы сообщить вам, я выбрал совершенно другой путь. В моем случае есть только 2 типа файлов, вероятность того, что любой файл будет бинарным, высока. Так

  1. предположить, что файл является двоичным, попробуйте делать то, что, как предполагается, должно быть сделано (например, Deserialize)
  2. поймать исключение
  3. лакомство файл в текстовом
  4. , если это не удается, что-то не так с самого файла
+0

Я думаю, что это лучший подход. Вы действительно волнуете, что такое тип файла? Или вам все равно, можете ли вы с ним что-то делать. Во многих случаях, если вы можете делать эти вещи, вам не нужно действительно знать, что такое тип. – stackexchanger

10

Пробег file -bi {filename}. Если все, что возвращается, начинается с «text /», то оно не является двоичным, иначе оно есть. ;-)

+1

Кажется, что есть «приложение/javascript» и «application/xml». Глядя здесь http://en.wikipedia.org/wiki/Internet_media_type, это говорит о том, что это не так просто. – Aaron

+1

Вы можете проверить с помощью 'file -i {filename}' и проверить там НЕ 'charset = binary'. –

+0

Должен сказать, что я был не совсем серьезно, когда я ответил выше. Текстовые файлы - это просто двоичные файлы, которые интерпретируются определенным образом. Если вы имели в виду, что что-то US-ASCII, то вы можете проверить каждый байт и посмотреть, соответствует ли оно вашему определению текста. Но, возможно, вы имели в виду * любой тип кодировки символов. Это будет намного сложнее. Особенно, если вы учитываете те, которые используют кодировку, основанную на энтропии (часто встречающиеся символы требуют меньше бит). С другой стороны, если вы имели в виду все US-ASCII, тогда кодированное изображение Base64 также было бы текстом? –

5

Я использовал этот код и он работает на английском и немецком языке довольно хорошо:

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

Идея интересная, но вместо replaceAll, которая бесполезно создает новую строку, я бы просто использовал цикл for для подсчета текста и нетекстовых символов. Ввод лимита в 1000 символов означает, что он не будет слишком дорогостоящим, но все равно бесполезная стоимость – miniBill

8

Я сделал это. Немного проще, но для латинских языков он должен работать нормально, с регулировкой отношения.

/** 
* 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

Спасибо за эту функцию. Одна вещь, с которой мне сложно разобраться, - это то, что происходит с возвращаемым значением: 'return (ascii + other) * 100/other> 95;' Что, если я что-то не хватает, всегда вернет true: В основном размер будет '1024', а также' data.length' и, следовательно, '(ascii + other)'. Итак, если '(ascii + other) * 100 == 102400' then' 102400/other> 95' => '102400> 95 * other' =>' other <1078' Это означает, что должно быть больше 1078 (из 1024) «другие» для этого, чтобы вернуть ложь, очевидно, невозможно. Возможно, вы имели в виду: '(other/size * 100> 95)' Или я что-то упускаю? – Inversus

+0

Я думаю, что ты прав. Исправлен код. –

+0

Прохладный прохладно. Я, я тоже с этим справился. Еще раз спасибо :) – Inversus

5

Использование 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

Это просто проверяет расширение файла, а не содержимое файла и, следовательно, бесполезно. – ares

+1

Это зависит от того, что установлено, согласно документам. – Adam

Смежные вопросы