Какие условия должны быть выполнены для того, чтобы файл был текстовым файлом, как определено POSIX?

22

POSIX определяет текстовый файл как:

Файл, содержащий символы, организованные в ноль или более строк. Строки не содержат символов NUL, и ни одна из них не может превышать длину {LINE_MAX} байтов, включая символ <newline>. Хотя POSIX.1-2017 не делает различий между текстовыми файлами и двоичными файлами (см. Стандарт ISO C), многие утилиты производят только предсказуемый или значимый вывод при работе с текстовыми файлами. Стандартные утилиты, имеющие такие ограничения, всегда указывают «текстовые файлы» в своих разделах STDIN или INPUT FILES.

Источник: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_403

Однако есть несколько вещей, которые я нахожу неясными:

  1. Должен ли текстовый файл быть обычным файлом? В приведенном выше отрывке явно не говорится, что файл должен быть обычным файлом.

  2. Может ли файл считаться текстовым файлом, если он содержит только один символ и только один символ (т. Е. Один символ, который не заканчивается новой строкой)? Я знаю, что этот вопрос может звучать неприметно, но они используют слово «символы» вместо «один или несколько символов». Другие могут не согласиться, но если они имеют в виду «один или несколько символов», я думаю, что они должны явно сказать это

  3. В приведенном выше отрывке он ссылается на «строки». Я нашел четыре определения со строкой в ​​их названии: «Пустая строка», «Показать строку», «Неполная строка» и «Строка». Должен ли я сделать вывод, что они означают «Строка» из-за пропуска слов «Пусто», «Показать» и «Неполный» - или все четыре из этих определений включительно считаются строкой в ​​приведенном выше отрывке?

Все вопросы, которые возникают после этого блока текста, зависят от вывода, что «символы» означают «один или несколько символов»:

  1. Можно ли с уверенностью заключить, что если файл пустой, это не текстовый файл, поскольку он не содержит один или несколько символов?

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

  1. Означает ли «ноль» в «нуле или более строках», что файл все еще можно считать текстовым файлом, если он содержит один или несколько символов, которые не заканчиваются символом новой строки?

  2. Означает ли «ноль или более строк», что когда в игру вступает одна «Строка» (0 или более символов плюс завершающий символ новой строки), становится недопустимым, когда последняя строка является «Неполной строкой» (одна или несколько символы новой строки в конце файла)?

  3. Означает ли, что «ни одна [никакая строка] не может превышать {LINE_MAX} байт в длину, включая символ новой строки», означает ли это ограничение на количество символов, допустимое для любой данной «строки» в текстовом файле (кроме этого, значение LINE_MAX в Ubuntu 18.04 и FreeBSD 11.1 - это "2048")?

Гарольд Фишер
источник
Хороший вопрос, Гарольд! Делает для отличного обсуждения терминологии. Жаль, что я не мог ответить на этот вопрос больше раз
Сергей Колодяжный

Ответы:

23
  1. Должен ли текстовый файл быть обычным файлом? В приведенном выше отрывке явно не говорится, что файл должен быть обычным файлом.

    Нет; выдержка даже специально отмечает стандартный ввод как потенциальный текстовый файл. Другие стандартные утилиты, такие как make, в частности , использовать в символьный файл /dev/null в виде текстового файла .

  2. Может ли файл считаться текстовым файлом, если он содержит только один символ и только один символ (т. Е. Один символ, который не заканчивается новой строкой)?

    Этот символ должен быть <newline>, или это не строка , и поэтому файл, в котором он находится, не является текстовым файлом. Файл, содержащий ровно байт 0A, является однострочным текстовым файлом. Пустая строка является допустимой строкой.

  3. В приведенном выше отрывке он ссылается на «строки». Я нашел четыре определения со строкой в ​​их названии: «Пустая строка», «Показать строку», «Неполная строка» и «Строка». Должен ли я сделать вывод, что они означают «Строка» из-за пропуска слов «Пусто», «Показать» и «Неполный»?

    Это на самом деле не вывод, а просто то, что говорится. Слову «линия» дано контекстно-соответствующее определение, и это то, о чем идет речь.

  4. Можно ли с уверенностью заключить, что если файл пустой, это не текстовый файл, поскольку он не содержит один или несколько символов?

    Пустой файл состоит из нуля (или более) строк и, таким образом, является текстовым файлом.

  5. Означает ли «ноль» в «нуле или более строках», что файл все еще можно считать текстовым файлом, если он содержит один или несколько символов, которые не заканчиваются символом новой строки?

    Нет, эти символы не организованы в линии.

  6. Означает ли «ноль или более строк», что когда в игру вступает одна «Строка» (0 или более символов плюс завершающий символ новой строки), становится недопустимым, когда последняя строка является «Неполной строкой» (одна или несколько символы новой строки в конце файла)?

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

  7. Означает ли, что «ни одна [никакая строка] не может превышать длину {LINE_MAX} байт, включая символ новой строки», означает ли это ограничение на количество символов, допустимое для любой данной «строки» в текстовом файле

    Да.

Это определение просто пытается установить некоторые границы того ,grep что определенно будет принимать текстовая утилита ( например, ) - и ничего более. Они также могут свободно принимать вещи более свободно, и довольно часто они делают это на практике. Им разрешается использовать буфер фиксированного размера для обработки строки, предполагать, что новая строка появляется до ее заполнения, и так далее. Вы можете читать слишком много вещей.

Майкл Гомер
источник
1
Ты уверен насчет пункта 2? Стандарт прямо заявляет « 0 или более строк». Так printf "a" > fileбы создать текстовый файл в соответствии с этим определением. Ваш ответ на 4, кажется, противоречит вашим ответам на 2 и 5, так как вы предлагаете, что touch fileсоздает текстовый файл, а printf "a" > fileне.
Тердон
4
@terdon: Я не вижу никакого противоречия в ответе Майкла. По сути, он, кажется, говорит, что текстовый файл POSIX - это любой файл, содержимое которого соответствует регулярному выражению (.{0,M}\n)*(неявно закреплен и имеет оба конца), где \nсоответствует .символу новой строки и соответствует любому символу, который не является символом новой строки, и Mявляется заполнителем для числового значения. LINE_MAX-1. В частности, это означает, что пустой файл является допустимым текстовым файлом, состоящим из нулевых строк, но любой непустой текстовый файл должен заканчиваться символом новой строки (поскольку в противном случае он будет содержать неполную строку, а неполная строка не является строкой ).
Илмари Каронен
@Michael Homer Что касается обычного файла, есть ли другие примеры, кроме / dev / null? На самом деле это не текстовый файл, поскольку он содержит один или несколько нулевых символов.
Гарольд Фишер
1
@HaroldFischer /dev/null- пустой файл. Вы думаете о /dev/zero.
Майкл Гомер
@HaroldFischer, нет, /dev/nullчитается как пустой, так как вы не получаете данных, когда читаете его. Я не уверен, что имеет смысл рассматривать нестандартные файлы здесь, поскольку многие из них имеют динамический характер. Это включает в себя каналы, сокеты, символьные устройства, которые в основном являются просто транспортными интерфейсами к / от какого-либо другого объекта. Они не содержат статического набора данных, поэтому имеет смысл рассмотреть свойства данных, которые были переданы, а не свойства файла .
ilkkachu
7

Как определено POSIX:

Да, текстовый файл (в основном):

Файл, содержащий символы, организованные в ноль или более строк.

Было бы полезно также включить следующие определения:

3.92 Строка символов

Непрерывная последовательность символов, оканчивающаяся первым нулевым байтом и включающая его.

3.195 Неполная линия

Последовательность из одного или нескольких не <newline> символов в конце файла.

3.206 Линия

Последовательность из нуля или более не-символов <newline> плюс завершающий символ <newline>.

3.243 Символ новой строки (<новая строка>)

Символ, который в выходном потоке указывает, что печать должна начинаться в начале следующей строки. Это символ, обозначенный '\ n' на языке Си. Не определено, является ли этот символ точной последовательностью, передаваемой в устройство вывода системой для выполнения перехода к следующей строке.

3.247 NUL

Символ со всеми битами, установленными в ноль.

Обратите внимание, что «Текстовый файл» не должен содержать байтов NUL.


Так:

  1. Должен ли текстовый файл быть обычным файлом?
    Нет, так не должно быть. «Текстовый файл» определяется с точки зрения того, что он содержит при чтении. Если файл содержит «ноль или более строк», это текстовый файл. Некоторые файлы, например /dev/stdin, могут содержать текстовый файл, если они читаются за один раз, а не при следующем чтении.
  2. Можно ли считать файл текстовым файлом, если он содержит только один символ и один символ…?
    Нет, это неполная строка (3.195).
    Текстовый файл должен иметь только неполную строку.
  3. Должен ли я сделать вывод, что они означают «Линия»…?
    Да, ты должен.
  4. Могу ли я безопасно сделать вывод, что если файл пустой, это не текстовый файл ...?
    Нет, пустой файл (ноль символов) является допустимым «текстовым файлом».
    Сверху: … ноль или более строк… . Ноль строк (ноль символов) является допустимым «Текстовым файлом».
  5. … Считается текстовым файлом, если он содержит один или несколько символов, которые не заканчиваются символом новой строки?
    Нет, «Неполная линия» не является (технически) действительной «строкой».
  6. Означает ли «ноль» в «нуле или более строках», что файл все еще можно считать текстовым файлом, если он содержит один или несколько символов, которые не заканчиваются символом новой строки?
    Нет, неполная строка не является «линией». Текстовый файл не должен содержать неполных строк.

  7. ... есть ограничение на количество символов, разрешенных в любой данной "строке" в текстовом файле ...?
    Да, в любой строке допустимого «текстового файла» должно быть разрешено не более {LINE_MAX} байтов (в отличие от символов).
    Значение {LINE_MAX} дается в файле <limit.h>
    (также читайте Размер буфера в формате разумных строк в C? ):

    {LINE_MAX}
    Если не указано иное, максимальная длина в байтах строки ввода утилиты (либо стандартного ввода, либо другого файла), когда утилита описывается как обработка текстовых файлов. Длина включает в себя место для трейлинга.
    Минимально допустимое значение: {_POSIX2_LINE_MAX}

    Для системы на основе GNU не существует установленного ограничения (кроме памяти) :

    Макрос: int LINE_MAX
    Самая большая текстовая строка, которую могут поддерживать текстовые утилиты POSIX.2. (Если вы используете GNU-версии этих утилит, то фактического ограничения не существует, за исключением ограничений, налагаемых доступной виртуальной памятью, но библиотека никак не может вам это сказать.)

    Кажется, он определен posix_lim.hкак 2048 (по крайней мере для 64-битных систем Linux Linux):

    $ grep -ri 'POSIX2_LINE_MAX' /usr/include/ 
    
    /usr/include/x86_64-linux-gnu/bits/xopen_lim.h:#define NL_LANGMAX       _POSIX2_LINE_MAX
    /usr/include/x86_64-linux-gnu/bits/posix2_lim.h:#define _POSIX2_LINE_MAX                2048
    /usr/include/x86_64-linux-gnu/bits/posix2_lim.h:#define LINE_MAX                _POSIX2_LINE_MAX
    

    Его также можно найти с помощью утилиты POSIX getconf :

    $ getconf LINE_MAX
    2048
    

Связанный: Почему текстовые файлы должны заканчиваться символом новой строки?

Исаак
источник
2
Этот ответ в основном правильный, но правильный ответ «должен ли текстовый файл быть обычным файлом» - нет . Любой вид файла может быть текстовым файлом, это вопрос содержания, тип файла не имеет значения. fileУтилита сообщает только тип файла для специальных файлов, но это только как подсобные работы, использование file - <…или (Linux) , file -s …чтобы увидеть его эвристики на содержимое файла для специального файла. Каждый раз, когда вы открываете его, специальный файл может иметь различное содержимое, поэтому он может быть или текстовым файлом каждый раз. /dev/nullвсегда текстовый файл, потому что его содержимое всегда является текстовым файлом.
Жиль "ТАК - перестань быть злым"
1
Вместо того, чтобы использовать grepфайлы, вы можете использовать getconfдля получения системных значений conf, например getconf LINE_MAX, которые, кстати, возвращают 2048 (байт) в моей системе (Ubuntu 16.04).
Heemayl
Я хотел найти файл, в котором была определена переменная, поэтому grep был необходим, и сделал свою работу (довольно быстро). Но да, getconfпозволяет прочитать текущее значение конфига.
Исаак