Как я могу различить «двоичные» и «текстовые» файлы? - PullRequest
58 голосов
/ 20 февраля 2009

Неофициально, большинство из нас понимают, что существуют «двоичные» файлы (объектные файлы, изображения, фильмы, исполняемые файлы, собственные форматы документов и т. Д.) И «текстовые» файлы (исходный код, файлы XML, HTML-файлы, электронная почта и т. Д.). ).

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

Однако существуют различные инструменты, которые работают с широким диапазоном файлов, и с практической точки зрения вы хотите сделать что-то другое в зависимости от того, является ли файл «текстовым» или «двоичным». Примером этого является любой инструмент, который выводит данные на консоль. Обычный «текст» будет хорошо смотреться и будет полезен. «двоичные» данные портят ваш терминал и, как правило, бесполезны для просмотра. GNU grep по крайней мере использует это различие при определении, должен ли он выводить совпадения на консоль.

Итак, вопрос в том, как определить, является ли файл «текстовым» или «двоичным»? И чтобы ограничить это дальше, как вы скажете на Linux, как файловая система? Мне неизвестны какие-либо метаданные файловой системы, которые указывают «тип» файла, поэтому вопрос, который я проверяю, проверяет содержимое файла: «текстовый» или «двоичный»? А для простоты давайте ограничим «текст» символами, которые можно распечатать на консоли пользователя. И, в частности, как бы вы реализовали это? (Я думал, что это подразумевается на этом сайте, но я думаю, что в целом полезно указать на существующий код, который делает это, я должен был указать), я не совсем понимаю, какие существующие программы я могу использовать для выполнения это.

Ответы [ 11 ]

62 голосов
/ 20 февраля 2009

Вы можете использовать команду file. Он проверяет файл (man file), чтобы определить, является ли он двоичным или текстовым. Вы можете посмотреть / позаимствовать его исходный код, если вам нужно сделать это из C.

file README
README: ASCII English text, with very long lines

file /bin/bash
/bin/bash: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.5, dynamically linked (uses shared libs), stripped
13 голосов
/ 20 февраля 2009

Программное обеспечение для работы с электронными таблицами, разработанное моей компанией, считывает ряд двоичных форматов, а также текстовые файлы.

Сначала мы рассмотрим первые несколько байтов для магического числа , которое мы узнаем. Если мы не распознаем магическое число любого из двоичных типов, которые мы читаем, то мы просматриваем до первых 2 Кбайт файла, чтобы увидеть, является ли он UTF-8 , UTF-16 или текстовый файл, закодированный в текущей кодовой странице операционной системы хоста. Если он не проходит ни одного из этих тестов, мы предполагаем, что это не тот файл, с которым мы можем иметь дело, и генерируем соответствующее исключение.

13 голосов
/ 20 февраля 2009

Вы можете определить MIME-тип файла с помощью

file --mime FILENAME

Сокращение: file -i в Linux и file -I (заглавная i) в macOS (см. Комментарии).

Если он начинается с text/, это текст, в противном случае - двоичный файл. Единственным исключением являются приложения XML. Вы можете сопоставить их с поиском +xml в конце типа файла.

4 голосов
/ 20 февраля 2009

Хорошо, если вы просто просматриваете весь файл, посмотрите, можно ли печатать каждый символ с isprint(c). Это немного сложнее для Unicode.

Чтобы различить текстовый файл в юникоде, MSDN предлагает несколько полезных советов о том, что делать .

Суть в том, чтобы сначала проверить до первых четырех байтов:

EF BB BF     UTF-8 
FF FE        UTF-16, little endian 
FE FF        UTF-16, big endian 
FF FE 00 00  UTF-32, little endian 
00 00 FE FF  UTF-32, big-endian 

Это скажет вам кодировку. Затем вы хотите использовать iswprint(c) для остальных символов в текстовом файле. Для UTF-8 и UTF-16 вам необходимо проанализировать данные вручную, так как один символ может быть представлен переменным числом байтов. Кроме того, если вы действительно анальный, вы захотите использовать вариант локали iswprint, если он доступен на вашей платформе.

3 голосов
/ 30 января 2013

Perl имеет приличную эвристику. Используйте оператор -B, чтобы проверить двоичный файл (и его противоположность, -T, чтобы проверить текст). Вот командная строка для вывода текстовых файлов:

$ find . -type f -print0 | perl -0nE 'say if -f and -s _ and -T _'

(Обратите внимание, что эти подчеркивания без предшествующего доллара верны (RTFM).)

2 голосов
/ 24 апреля 2017

Чтобы вывести имена текстовых файлов в текущем каталоге / подкаталогах:

$ grep -rIl ''

Бинарные:

$ grep -rIL ''

Чтобы проверить определенный файл, слегка измените команду:

$ grep -qI '' FILE

тогда выход из состояния «0» будет означать, что файл является текстом; «1» - двоичный Мог проверить:

$ echo $?

2 голосов
/ 23 мая 2015

Это старая тема, но, возможно, кто-то найдет это полезным. Если вам нужно в скрипте решить, является ли что-то файлом, вы можете просто сделать так:

if file -i $1 | grep -q text;
then 
.
.
fi

Это позволит получить тип файла, и с помощью команды grep grep вы можете решить, будет ли это текст.

2 голосов
/ 20 февраля 2009

Большинство программ, которые пытаются определить разницу, используют эвристику, например, проверяют первые n байтов файла и проверяют, соответствуют ли эти байты все тексту или нет (т.е. все ли они попадают в диапазон печатаемых символов ASCII). Для лучшего понимания всегда есть команда file в UNIX-подобных системах.

1 голос
/ 23 июня 2016

Вы можете использовать libmagic, который является библиотечной версией командной строки Unix file.

Есть обертка для многих языков:

1 голос
/ 20 февраля 2009

Как уже говорилось, * операционные системы nix имеют эту возможность в команде file. Эта команда использует файл конфигурации, который определяет магические числа, содержащиеся во многих популярных файловых структурах.

Этот файл, называемый магией, исторически хранился в / etc, хотя в некоторых дистрибутивах он может находиться в / usr / share. Волшебный файл определяет смещения значений, о которых известно, что они существуют в файле, и может затем изучить эти местоположения, чтобы определить тип файла.

Структуру и описание магического файла можно найти на соответствующей странице справочника (man magic)

Что касается реализации, то ее можно найти в самом файле file.c , однако соответствующая часть команды file, определяющая, является ли текст читаемым, или нет, является следующей

/* Make sure we are dealing with ascii text before looking for tokens */
    for (i = 0; i < nbytes - 1; i++) {
        if (!isascii(buf[i]) ||
            (iscntrl(buf[i]) && !isspace(buf[i]) &&
             buf[i] != '\b' && buf[i] != '\032' && buf[i] != '\033'
            )
           )
            return 0;   /* not all ASCII */
    }
...