Який останній символ у файлі?


19

Я просто прочитав відповіді на тему "Видалення символу нового рядка в кінці файлу", і всі сказали, щоб видалити останній символ. Моє запитання: чи не останній символ eof?



1
@SorenBjornstad Я також хотів би додати, що коли в кінці текстового файлу Unix є новий рядок, він є, тому що він закінчує останній рядок. Порожній текстовий файл не має нового рядка в кінці: це послідовність нульових символів.
Каз

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 повертається до прочитаного системного виклику поверненням рядка символів до абонента. За умовою, повернене нульове значення з системного виклику читання (тобто зчитування нульових символів) сигналізує про закінчення стану файлу. Однак вхідний файл не закривається автоматично, і, якщо вхід надходить з терміналу, він не ставиться в стан "кінець файлу". Ви можете написати програму, яка продовжує читати з терміналу, навіть після "закінчення файлу", і виклик читання може повернути не нуль для наступного рядка введення.

  • Аналогія між символами eof та eol можна побачити, якщо Ctrl- Dнатиснуто, коли на рядку вже записано деякий вхід. Наприклад, якщо ви пишете "abc" і натискаєте Ctrl- Dчитання дзвінка повертається, цього разу зі значенням повернення 3 та з "abc", що зберігається в буфері, передається як аргумент. Оскільки читання не повертає 0, це не трактується як умова EOF вищезгаданою конвенцією. Аналогічно, натискання клавіші return для повернення зчитуваного дзвінка робить увесь рядок введення (включаючи новий рядок). Ви можете спробувати це за допомогою catкоманди: напишіть кілька рядків у рядку та натисніть Ctrl- D. Ви побачите, як персонажі повторюються до вас і catчекаєте додаткового введення.

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


19

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

У системах, подібних Unix, немає потреби в EOFперсонажі; жоден не використовується. Система може вказати програмам, скільки байтів у файлі:

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

    У випадку з VMS, обмеження було пов’язане з тим, як працює час виконання C. Програми на мові збірки можуть (і зробили) отримати правильний розмір файлу.

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

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

До речі, файли не повинні закінчуватися символом нового рядка (ASCII-рядок). Текстові редактори можуть впоратися з файлами, які є всіма текстами для друку, але не мають зворотного нового рядка.


8
POSIX визначає текстовий файл як файл, що містить послідовність рядків і, у свою чергу, кожен рядок як послідовність символів, які не є новими рядками, а за ними - один новий рядок. Таким чином, файл, що закінчується чим-небудь, окрім 0x0A, не є відповідним текстовим файлом.
Даміан Єррік

2
Мені це відомо, саме тому я зазначив, що текстові редактори працюють. (Бінарні файли не мають такого обмеження).
Томас Дікі

Дійсно варто відзначити, що файли, призначені для обробки як текст, який не має зворотного нового рядка, як і раніше, мабуть, погана форма (навіть якщо типові редактори тексту були закодовані для компенсації таких файлів), принаймні, якщо ви насправді хочете, щоб це було широко зручні / сумісні, тому що відсутність нового рядка може створювати додаткові труднощі за різних обставин (об'єднання / друк декількох текстових файлів, аналіз типових інструментів командного рядка, мінімальні редактори, такі як busyboxs 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 - не персонаж, а особливий статус файлу)
Stig Hemmer
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.