Какой последний символ в файле?

19

Я только что прочитал ответы на «Удаление символа новой строки в конце файла», и все сказали, чтобы удалить последний символ. Мой вопрос, разве не последний персонаж?

sworwitz
источник
11
EOF это не персонаж .
Сорен Бьорнстад
1
@SorenBjornstad Я также хотел бы добавить, что когда в конце текстового файла Unix есть символ новой строки, он появляется там, потому что он завершает последнюю строку. Пустой текстовый файл не имеет новой строки в конце: это последовательность нулевых символов.
Kaz
3
Чтобы быть слегка педантичным, CPM и DOS использовали ^ Z в качестве символа EOF, и вы все равно иногда можете встретить файлы, заканчивающиеся на ^ Z.
Эдвард Фальк

Ответы:

13

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

  • Набор символов ASCII не содержит точного символа EOF. Существует несколько управляющих символов «конец»: Конец текста (3), Конец передачи (4), Конец передачи блока (23), Конец среды (25). File Separator (28), возможно, ближе всего подходит к символу EOF. Код 26 - «Заменитель», а не EOF.

  • Ctrl- Dсвязан только с терминальным входом. Например, команда cat filea fileb filec > outfileне включает Ctrl- D. Кстати, вы можете изменить символ терминала EOF на что-то другое Ctrl- Dиспользуя sttyкоманду.

  • Строго говоря, Ctrl- D(или что бы вы ни изменили) не является кодом ключа EOF. То, что он делает, это заставляет readсистемный вызов возвращаться с тем, какой ввод доступен, так же, как нажатие return заставляет системный вызов read возвращать строку символов вызывающей стороне. По соглашению, возвращаемое значение нуля из системного вызова read (то есть чтение нулевых символов) сигнализирует об окончании состояния файла. Однако входной файл не закрывается автоматически, и, если ввод поступает с терминала, он не переводится в состояние «конец файла». Вы можете написать программу, которая продолжает чтение с терминала даже после «конца файла», и вызов read может возвращать ненулевое значение для следующей строки ввода.

  • Аналогию между символами eof и eol можно увидеть, если Ctrl- Dнажата, когда какой-либо ввод уже записан в строке. Например, если вы пишете «abc» и нажимаете Ctrl- Dвызов read возвращается, на этот раз с возвращаемым значением 3 и с «abc», хранящимся в буфере, передаваемом в качестве аргумента. Поскольку read не возвращает 0, это не интерпретируется как условие EOF согласно соглашению выше. Точно так же нажатие кнопки возврата к возвращает вызов чтения со всей строкой ввода (включая перевод строки). Вы можете попробовать это с помощью catкоманды: напишите несколько символов в строке и нажмите Ctrl- D. Вы увидите, что персонажи возвращаются к вам и catожидают большего ввода.

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

Йохан Мирен
источник
19

Управляющие символы ASCII имеют определения 1960-х годов (фактически предшествующие тому, что вы могли бы считать сетью ). Не все эти управляющие символы используются так, как они были определены для телекоммуникационного оборудования в то время.

В Unix-подобных системах нет необходимости в EOFперсонаже; ни один не используется. Система может сообщить приложениям, сколько байтов находится в файле:

  • В некоторых других системах (видимых в VMS, DOS, Windows) control-Z может действовать как маркер конца файла, потому что в более старых версиях система не могла сообщить некоторым приложениям, сколько байтов в файле.

    В случае VMS ограничение было связано с тем, как работала среда выполнения C. Приложения на языке ассемблера могли (и делали) получить правильный размер файла.

  • Системы Unix в оболочке обычно используют control-D, чтобы сообщить приложению, что достигнут конец ввода (файла), но control-D не сохраняется в файле.

В C EOFспециально сделано, -1чтобы указать, что это недопустимый символ. Стандартный ввод / вывод возвращается EOFпри обнаружении условия конца файла, а не специального символа.

Кстати, файлы не должны заканчиваться символом перевода строки (ASCII-перевод строки). Текстовые редакторы могут работать с файлами, которые представляют собой печатный текст, но не содержат завершающей строки.

Томас Дики
источник
8
POSIX определяет текстовый файл как файл, содержащий последовательность строк и, в свою очередь, каждую строку как последовательность символов не-новой строки, за которой следует одна новая строка. Таким образом, файл, заканчивающийся чем-либо, кроме 0x0A, не является соответствующим текстовым файлом.
Дамиан Йеррик
2
Я знаю об этом, поэтому я указал, что текстовые редакторы работают. (Бинарные файлы не имеют такого ограничения).
Томас Дики
Стоит отметить, что файлы, предназначенные для обработки в виде текста, в котором нет завершающего символа новой строки, по-прежнему, вероятно, являются плохой формой (даже если типичные текстовые редакторы были закодированы для компенсации таких файлов), по крайней мере, если вы действительно хотите, чтобы это было в целом удобный для пользователя / совместимый, потому что отсутствие завершающего перевода строки может добавить дополнительные трудности в различных обстоятельствах (объединение / печать нескольких текстовых файлов, анализ с помощью типичных инструментов командной строки, минимальные редакторы, такие как busybox's vi, и т. д.).
mtraceur
(1) До VMS, RT-11 RSX-11 TOPS-10 имел файловые системы только с точностью до блока и нуждался в символе EOF. То же самое сделал CP / M, который, очевидно, скопировал его из DEC и в свою очередь скопировал в раннюю MS-DOS, а затем передал Windows. (2) В Unix это драйвер tty, а не оболочка, как более подробно описано в JohanM, хотя люди обычно запускают оболочки на устройствах tty.
dave_thompson_085
Конечно - DEC был там (и заметьте, что я упомянул более старые версии). Будет ли это происхождение функции CP / M было бы интересной темой для изучения (не здесь); Я упомянул эти случаи, чтобы дать некоторое представление об альтернативах.
Томас Дики
7

EOF не персонаж. Это состояние, которое указывает, что больше нет символов для чтения из файлового потока. Когда вы вводите команду EOF из терминала, вы даете сигнал ОС закрыть входной поток, не вводя специальный символ.

Мунир
источник
1
Да, но в ASCII-таблице EOF равно 26, поэтому я подумал, что последний байт был двоичным представлением 26. Итак, как может программа, которая читает ввод, знать, где он заканчивается?
Sworwitz
ASCII предназначался для передачи информации по сети. В этом случае вам нужен персонаж EOF. (В ASCII также было много управляющих кодов. Не все можно было распечатать.) В случае файловых потоков размер файла уже известен через файловую систему, поэтому ОС может определить, когда больше нет данных для чтения.
Мунир
@sworwitz: Что касается C, входные функции чтения, которые возвращают символ за вызов, возвращают int (обычно 32-битное число, но должно быть минимум 16 бит), а не символ. Функция сигнализирует и EOF, возвращая -1 (0xffffffff), который не является допустимым 8-битным значением, поэтому он не будет перепутан ни с каким символом ASCII, даже с 0xff. Функции, которые возвращают строку, также возвращают длину прочитанных данных. Эта длина может использоваться, чтобы сигнализировать об отсутствии данных или об окончании данных (опять же, длина может быть -1). Наконец, есть также функция, которую вы можете вызвать, которая сообщит вам, достиг ли поток конца
slebetman
Хорошо спасибо! Поэтому, когда в bash я нажимаю Ctrl + d, я даю на вход символ ASCII, верно?
Sworwitz
@sworwitz Не совсем. Прежде чем bashполучить в свои руки вход, он массируется драйвером TTY. Этот драйвер перехватывает Ctrl-D и отправляет EOF bash (где EOF не символ, а особый статус файла)
Стиг Хеммер