Как я могу отличить "двоичные" и "текстовые" файлы?
неофициально большинство из нас понимает, что существуют "двоичные" файлы (объектные файлы, изображения, фильмы, исполняемые файлы, проприетарные форматы документов и т. д.) и "текстовые" файлы (исходный код, XML-файлы, HTML-файлы, электронная почта и т. д.).
В общем, вам нужно знать содержимое файла, чтобы иметь возможность делать с ним что-либо полезное, и сформировать эту точку зрения, если кодировка "двоичная" или "текстовая", это действительно не имеет значения. И, конечно же, файлы просто хранят байты данных, поэтому они все "двоичные" и "текст" ничего не значит, не зная кодировки. И все же, по-прежнему полезно говорить о "двоичных" и "текстовых" файлах, но чтобы не обидеть кого-либо с этим неточным определением, я буду продолжать использовать "пугающие" цитаты.
тем не менее, существуют различные инструменты, которые работают с широким спектром файлов, и на практике вы хотите сделать что-то другое в зависимости от того, является ли файл "текстовым" или "двоичным". Примером этого является любой инструмент, который выводит данные на консоль. Простой "текст" будет выглядеть хорошо, и полезно. "двоичные" данные портят ваш терминал, и, как правило, не полезно смотреть. GNU grep по крайней мере использует это различие при определении того, следует ли выводить совпадения на консоль.
Итак, вопрос в том, как вы определяете, является ли файл "текстовым" или "двоичным"? И ограничивать дальше, как вы скажете на Linux, как файловая система? Я не знаю никаких метаданных файловой системы, которые указывают на " тип " файла, поэтому вопрос далее становится, по проверяя содержимое файла, как я могу определить, является ли он "текстовым" или "двоичным"? И для простоты, давайте ограничим "текст" для обозначения символов, которые могут быть напечатаны на консоли пользователя. И в частности как бы вы реализовать этого? (Я думал, что это подразумевалось на этом сайте, но я думаю, что это полезно, в общем, указать на существующий код, который делает это, я должен был указать), я действительно не после того, какие существующие программы я могу использовать для этого.
11 ответов:
электронная таблица программное обеспечение моя компания делает читает ряд двоичных форматов файлов, а также текстовые файлы.
мы сначала посмотрим на первые несколько байт магическое число что мы признаем. Если мы не распознаем магическое число любого из двоичных типов, которые мы читаем, то мы смотрим на первые 2K байт файла, чтобы увидеть, является ли он UTF-8,UTF-16 или текстовый файл, закодированный в текущем страницу код of операционная система хоста. Если он не проходит ни один из этих тестов, мы предполагаем, что это не файл, с которым мы можем иметь дело, и выбрасываем соответствующее исключение.
вы можете определить тип MIME файла
file --mime FILENAMEитог:
file -iна Linux иfile -I(capital i) на macOS (см. комментарии).если он начинается с
text/, Это текст, иначе двоичный. Единственным исключением являются XML-приложения. Вы можете соответствовать тем, кто ищет+xmlв конце типа файла.
Ну, если вы просто проверяете весь файл, посмотрите, можно ли печатать каждый символ с помощью
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если это доступно на вашей платформе.
Perl имеет неплохой эвристический. Используйте
-Bоператор для проверки двоичного кода (и его противоположность,-Tдля проверки текста). Вот оболочка однострочный список текстовых файлов:$ find . -type f -print0 | perl -0nE 'say if -f and -s _ and -T _'(обратите внимание, что эти подчеркивания без предыдущего доллара являются правильными (RTFM).)
большинство программ, которые пытаются определить разницу, используют эвристику, например, исследуя первый n байт файла и посмотреть, если эти байты все квалифицируйте как "текст" или нет (т. е. все ли они попадают в диапазон печатаемых символов ASCII). Для более точного уникален всегда команду "Файл" на UNIX-подобных системах.
Это старая тема, но, может быть, кто-то найдет это полезным. Если вам нужно решить в скрипте, если что-то является файлом, то вы можете просто сделать так:
if file -i | grep -q text; then . . fiЭто будет получить тип файла, и с молчаливым grep вы можете решить, если его текст.
Как уже говорилось ранее * операционные системы nix имеют эту возможность в команде file. Эта команда использует файл конфигурации, который определяет магические числа, содержащиеся во многих популярных файловых структурах.
этот файл, называемый magic, исторически хранился в /etc, хотя это может быть в /usr/share в некоторых дистрибутивах. Волшебный файл определяет смещения значений, которые, как известно, существуют в файле, а затем может исследовать эти местоположения, чтобы определить тип файл.
структуру и описание файла magic можно найти, обратившись к соответствующей странице руководства (man magic)
что касается реализации, хорошо, что можно найти в .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] != '2' && buf[i] != '3' ) ) return 0; /* not all ASCII */ }
В списке имен текстовый файл в текущей директории/подкаталоги:
$ grep -rIl ''файлы:
$ grep -rIL ''чтобы проверить конкретный файл, команду немного изменить:
$ grep -qI '' FILEтогда статус выхода ' 0 'будет означать, что файл является текстом;' 1 ' - двоичный. Мог бы проверить:
$ echo $?
Comments