company_banner

EOF — это не символ

Автор оригинала: Ruslan Spivak
  • Перевод
Недавно я читал книгу «Компьютерные системы: архитектура и программирование. Взгляд программиста». Там, в главе про систему ввода-вывода Unix, авторы упомянули о том, что в конце файла нет особого символа EOF.



Если вы читали о системе ввода-вывода Unix/Linux, или экспериментировали с ней, если писали программы на C, которые читают данные из файлов, то это заявление вам, вероятно, покажется совершенно очевидным. Но давайте поближе присмотримся к следующим двум утверждениям, относящимся к тому, что я нашёл в книге:

  1. EOF — это не символ.
  2. В конце файлов нет некоего особого символа.

Что же такое EOF?

EOF — это не символ


Почему кто-то говорит или думает, что EOF — это символ? Полагаю, это может быть так из-за того, что в некоторых программах, написанных на C, можно найти код, в котором используется явная проверка на EOF с использованием функций getchar() и getc().

Это может выглядеть так:

    #include <stdio.h>
    ...
    while ((c = getchar()) != EOF)
      putchar(c);

Или так:

    FILE *fp;
    int c;
    ...
    while ((c = getc(fp)) != EOF)
      putc(c, stdout);

Если заглянуть в справку по getchar() или getc(), можно узнать, что обе функции считывают следующий символ из потока ввода. Вероятно — именно это является причиной возникновения заблуждения о природе EOF. Но это — лишь мои предположения. Вернёмся к мысли о том, что EOF — это не символ.

А что такое, вообще, символ? Символ — это самый маленький компонент текста. «A», «a», «B», «b» — всё это — разные символы. У символа есть числовой код, который в стандарте Unicode называют кодовой точкой. Например — латинская буква «A» имеет, в десятичном представлении, код 65. Это можно быстро проверить, воспользовавшись командной строкой интерпретатора Python:

$python
>>> ord('A')
65
>>> chr(65)
'A'

Или можно взглянуть на таблицу ASCII в Unix/Linux:

$ man ascii


Выясним, какой код соответствует EOF, написав небольшую программу на C. В ANSI C константа EOF определена в stdio.h, она является частью стандартной библиотеки. Обычно в эту константу записано -1. Можете сохранить следующий код в файле printeof.c, скомпилировать его и запустить:

#include <stdio.h>

int main(int argc, char *argv[])
{
  printf("EOF value on my system: %d\n", EOF);
  return 0;
}

Скомпилируем и запустим программу:

$ gcc -o printeof printeof.c

$ ./printeof
EOF value on my system: -1

У меня эта программа, проверенная на Mac OS и на Ubuntu, сообщает о том, что EOF равняется -1. Есть ли какой-нибудь символ с таким кодом? Тут, опять же, можно проверить коды символов в таблице ASCII, можно взглянуть на таблицу Unicode и узнать о том, в каком диапазоне могут находиться коды символов. Мы же поступим иначе: запустим интерпретатор Python и воспользуемся стандартной функцией chr() для того, чтобы она дала бы нам символ, соответствующий коду -1:

$ python
>>> chr(-1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: chr() arg not in range(0x110000)

Как и ожидалось, символа с кодом -1 не существует. Значит, в итоге, EOF, и правда, символом не является. Переходим теперь ко второму рассматриваемому утверждению.

В конце файлов нет некоего особого символа


Может, EOF — это особенный символ, который можно обнаружить в конце файла? Полагаю, сейчас вы уже знаете ответ. Но давайте тщательно проверим наше предположение.

Возьмём простой текстовый файл, helloworld.txt, и выведем его содержимое в шестнадцатеричном представлении. Для этого можно воспользоваться командой xxd:

$ cat helloworld.txt
Hello world!

$ xxd helloworld.txt
00000000: 4865 6c6c 6f20 776f 726c 6421 0a         Hello world!.

Как видите, последний символ файла имеет код 0a. Из таблицы ASCII можно узнать о том, что этот код соответствует символу nl, то есть — символу новой строки. Это можно выяснить и воспользовавшись Python:

$ python
>>> chr(0x0a)
'\n'

Так. EOF — это не символ, а в конце файлов нет некоего особого символа. Что же такое EOF?

Что такое EOF?


EOF (end-of-file) — это состояние, которое может быть обнаружено приложением в ситуации, когда операция чтения файла доходит до его конца.

Взглянем на то, как можно обнаруживать состояние EOF в разных языках программирования при чтении текстового файла с использованием высокоуровневых средств ввода-вывода, предоставляемых этими языками. Для этого напишем очень простую версию cat, которая будет называться mcat. Она побайтно (посимвольно) читает ASCII-текст и в явном виде выполняет проверку на EOF. Программу напишем на следующих языках:

  • ANSI C
  • Python 3
  • Go
  • JavaScript (Node.js)

Вот репозиторий с кодом примеров. Приступим к их разбору.

ANSI C


Начнём с почтенного C. Представленная здесь программа является модифицированной версией cat из книги «Язык программирования C».

/* mcat.c */
#include <stdio.h>

int main(int argc, char *argv[])
{
  FILE *fp;
  int c;

  if ((fp = fopen(*++argv, "r")) == NULL) {
    printf("mcat: can't open %s\n", *argv);
    return 1;
  }

  while ((c = getc(fp)) != EOF)
    putc(c, stdout);

  fclose(fp);

  return 0;
}

Компиляция:

$ gcc -o mcat mcat.c

Запуск:

$ ./mcat helloworld.txt
Hello world!

Вот некоторые пояснения, касающиеся вышеприведённого кода:

  • Программа открывает файл, переданный ей в виде аргумента командной строки.
  • В цикле while осуществляется копирование данных из файла в стандартный поток вывода. Данные копируются побайтово, происходит это до тех пор, пока не будет достигнут конец файла.
  • Когда программа доходит до EOF, она закрывает файл и завершает работу.

Python 3


В Python нет механизма явной проверки на EOF, похожего на тот, который имеется в ANSI C. Но если посимвольно читать файл, то можно выявить состояние EOF в том случае, если в переменной, хранящей очередной прочитанный символ, будет пусто:

# mcat.py
import sys

with open(sys.argv[1]) as fin:
    while True:
        c = fin.read(1) # читаем максимум 1 символ
        if c == '':     # EOF
            break
        print(c, end='')

Запустим программу и взглянём на возвращаемые ей результаты:

$ python mcat.py helloworld.txt
Hello world!

Вот более короткая версия этого же примера, написанная на Python 3.8+. Здесь используется оператор := (его называют «оператор walrus» или «моржовый оператор»):

# mcat38.py
import sys

with open(sys.argv[1]) as fin:
    while (c := fin.read(1)) != '':  # читаем максимум 1 символ до достижения EOF
        print(c, end='')

Запустим этот код:

$ python3.8 mcat38.py helloworld.txt
Hello world!

Go


В Go можно явным образом проверить ошибку, возвращённую Read(), на предмет того, не указывает ли она на то, что мы добрались до конца файла:

// mcat.go
package main

import (
    "fmt"
    "os"
    "io"
)

func main() {
    file, err := os.Open(os.Args[1])
    if err != nil {
        fmt.Fprintf(os.Stderr, "mcat: %v\n", err)
        os.Exit(1)
    }

    buffer := make([]byte, 1)  // 1-byte buffer
    for {
        bytesread, err := file.Read(buffer)
        if err == io.EOF {
            break
        }
        fmt.Print(string(buffer[:bytesread]))
    }
    file.Close()
}

Запустим программу:

$ go run mcat.go helloworld.txt
Hello world!

JavaScript (Node.js)


В среде Node.js нет механизма для явной проверки на EOF. Но, когда при достижении конца файла делается попытка ещё что-то прочитать, вызывается событие потока end.

/* mcat.js */
const fs = require('fs');
const process = require('process');

const fileName = process.argv[2];

var readable = fs.createReadStream(fileName, {
  encoding: 'utf8',
  fd: null,
});

readable.on('readable', function() {
  var chunk;
  while ((chunk = readable.read(1)) !== null) {
    process.stdout.write(chunk); /* chunk is one byte */
  }
});

readable.on('end', () => {
  console.log('\nEOF: There will be no more data.');
});

Запустим программу:

$ node mcat.js helloworld.txt
Hello world!

EOF: There will be no more data.

Низкоуровневые системные механизмы


Как высокоуровневые механизмы ввода-вывода, использованные в вышеприведённых примерах, определяют достижение конца файла? В Linux эти механизмы прямо или косвенно используют системный вызов read(), предоставляемый ядром. Функция (или макрос) getc() из C, например, использует системный вызов read() и возвращает EOF в том случае, если read() указывает на возникновение состояния достижения конца файла. В этом случае read() возвращает 0. Если изобразить всё это в виде схемы, то получится следующее:


Получается, что функция getc() основана на read().

Напишем версию cat, названную syscat, используя только системные вызовы Unix. Сделаем мы это не только из интереса, но и из-за того, что это вполне может принести нам какую-то пользу.

Вот эта программа, написанная на C:

/* syscat.c */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
  int fd;
  char c;

  fd = open(argv[1], O_RDONLY, 0);

  while (read(fd, &c, 1) != 0)
    write(STDOUT_FILENO, &c, 1);

  return 0;
}

Запустим её:

$ gcc -o syscat syscat.c

$ ./syscat helloworld.txt
Hello world!

В этом коде используется тот факт, что функция read(), указывая на достижение конца файла, возвращает 0.

Вот та же программа, написанная на Python 3:

# syscat.py
import sys
import os

fd = os.open(sys.argv[1], os.O_RDONLY)

while True:
    c = os.read(fd, 1)
    if not c:  # EOF
        break
    os.write(sys.stdout.fileno(), c)

Запустим её:

$ python syscat.py helloworld.txt
Hello world!

Вот — то же самое, написанное на Python 3.8+:

# syscat38.py
import sys
import os

fd = os.open(sys.argv[1], os.O_RDONLY)

while c := os.read(fd, 1):
    os.write(sys.stdout.fileno(), c)

Запустим и этот код:

$ python3.8 syscat38.py helloworld.txt
Hello world!

Итоги


  • EOF — это не символ.
  • В конце файлов нет некоего особого символа.
  • EOF — это состояние, о котором сообщает ядро, и которое может быть обнаружено приложением в том случае, когда операция чтения данных доходит до конца файла.
  • В ANSI C EOF — это, опять же, не символ. Это — константа, определённая в stdio.h, в которую обычно записано значение -1.
  • «Символ» EOF нельзя найти в таблице ASCII или в Unicode.

Уважаемые читатели! А вы знаете о каких-нибудь более или менее широко распространённых заблуждениях из мира компьютеров?

RUVDS.com
VDS/VPS-хостинг. Скидка 10% по коду HABR10

Комментарии 63

    +27
    Понятно, что это копи-паста. Но статья откровенно слабенькая, и не несет в себе всей истины о EOF. Не увидел акцентов на граблях его применения. В основном приведены доказательства отсутствия символа EOF в разных вариациях.
      +2
      Как по мне — отличная статья, чтобы кидать ссылку в ответ тем, кто говорит что-то типа «теперь нажмите ctrl-d, чтобы ввести символ конца файла».
        +7
        ctrl+D (0x04) — символ конца передачи — для текстовых файлов, на мой взгляд, вполне можно называть концом файла ).
        Википедия: Управляющие символы
          +2
          Однако, данный ввод будет обработан не самим приложением, а операционной системой, я так понимаю? А в приложении это приведёт к тому, что вызов getchar() вернёт EOF? И что будет, если запайпить файл, содержащий символ 0x04 на вход какой-либо программы? Это ведь не будет обработано так же?
            +3

            Да, не будет, потому как поток-из-файла не то же самое, что поток-из-TTY. 0х04 спокойно пролезет в поток, а EOF будет выдан по окончанию передачи всех байт файла.

          –1
          char — целочисленный, а EOF определяется как -1, то есть FF. Соответственно, во время оно при считывании файла c помощью getc всё прекрасно остановливалось, если в файле был этот символ. Символом он является, потому что является возможным значением для char.
            +7
            getc() возвращает int, EOF (-1) и это не 0xff. Как себя будет вести ваша конструкция при чтении бинарного файла?
              0
              getc() возвращает int, EOF (-1) и это не 0xff.
              при считывании символа 0xFF функция возвращала именно -1, а не 0x000000ff
              Как себя будет вести ваша конструкция при чтении бинарного файла?
              а)Это не моя конструкция, б)getc() считывает символ 0xff. Возвращает -1. Типичный цикл считывания при этом прерывался, так что файл до физического конца не считывался. Это было одной из типичных ошибок и можно найти уйму рекомендаций не использовать эту функцию для работы с файлами, а только для чтения с консоли.
                +5

                Это в какой ОС?
                У меня man getc говорит "returns it as an unsigned char cast to an int".

                  +4
                  Вероятно имеется в виду поведение, наподобие описанного в
                  man7.org/linux/man-pages/man3/getc.3p.html
                  If the integer value returned by getc() is stored into a variable of
                  type char and then compared against the integer constant EOF, the
                  comparison may never succeed, because sign-extension of a variable of
                  type char on widening to integer is implementation-defined.


                  Тоже в своё время часто встречал, на Западе часто экономили на «unsigned » :)
              0
              Это, видимо, потому что код программы некорректный
                0
                конечно
            +12
            EOF — это символ, который генерируется нажатием CTRL+Z.
            В MS DOS он служил флагом окончания текстового файла. Кстати, если что-то дописать после этого символа, DOS не выводила эту дописку командой «type».

            C:\> copy con myfile.txt
            blah-blah-blah
            <CTRL+Z>
            C:\>

              +3

              В общем случае ^Z это символ замены, а не EOF.
              Тем не менее, в DOS он значил именно EOF, да

                +7
                И не только в DOS, а во многих старых системах, RSX-11, например. Собственно везде, где работали с перфолентами и перфокартами.

                Проблема была простая — как отличить обрыв перфоленты от её штатного конца? Вот для решения этой проблемы и придумали EOF. Ещё смешнее он выглядел на перфоркарте — это была отдельная карта. Самый смешной вариант для «отдельной перфокарты» — это ГОСТ 23057-78, стандарт FORTRAN: Заключительной строкой называется такая строка, которая в позициях 1-6 содержит пробелы, а в позициях 7-72 пробелы и буквы E, N и D.
                  0
                  Тепреь я хоть понял, откуда, вообще, пошла эта тема и эта дискуссия. Спасибо, ваш один комментарий ценнее всей статьи!
            +9
            Хе-хе, а вот в CP/M-80 был именно что символ EOF. Потому как файлы были кратны 128 байтам.
              +1

              И то ли сама MS-DOS, то ли некоторые программы более-менее корректно его обрабатывали

                +6
                Насколько я помню, на уровне стандартных библиотек (если открывать файл, как текстовый – дальше EOF не читался)

                А под DOS, емнип, были текстовые редакторы, которые в обычный текстовый файл после символа EOF записывали свою служебную информацию. Получалось, что команда type выдавала файл без неё, а редактор использовал.
                  +1
                  на уровне функции getc(), если быть точным.
                    +1
                    В Си — да, в Паскале – реализация операторов read/readln, в других языках ещё что-то…
                    А при написании под CP/M-80 на ассемблере (PL/M почему-то мне так и не попался) надо было всё делать руками :-)
                      +2
                      А при написании под CP/M-80 на ассемблере
                      Извините, не напугали :-)
                      На ассемблере — о каких таких стоп-символах вообще может речь?
                        0

                        Жалко, плюсик поставить не могу)


                        На ассемблере – ну, примерно о тех же, что на Си, только "закат солнца вручную". Т.е. обрабатывать их самому в соответствии с рекомендациями + не забывать о крайних случаях (сегодня освежал в памяти особенности работы с файлами в CP/M – наткнулся на обсуждение, нужен ли EOF, если размер файла кратен 128 байтам… Оказывается, не нужен)

                  0
                  del
                +10
                Если бы автор открыл файл в текстовом режиме под Windows*, то он мог бы обнаружить, что символ с кодом 0x1a вполне себе интерпретируется как признак конца файла.
                  +2
                  Управляющие символы ASCII
                  Номер Английское название Русское название
                  1A SUBSTITUTE символ замены
                  +2
                  Привет от Q[uick]BASIC. Откройте файл в текстовом режиме и EOF вполне себе станет символом.
                    +1
                    В чём отличие прочитанного байта 0xFF и EOF?
                      +1
                      Зависит от того, с чем его сравнить. Если с char, — то от реализации. В стандарте не указана ни размерность char, ни его знаковость.
                        +8
                        Это называется здравствуйте грабли.
                        Изначально getc() возвращает тип INT, и при этом символы кодируются беззнаковым unsigned char (byte).
                        Int EOF == ( -1 ) совсем не равен 0xFF.
                        А вот если считывать getc() в char, и при этом не читать варнинги при компиляции, получим EOF == 0xFF
                          0
                          А вот если считывать getc() в char, и при этом не читать варнинги при компиляции, получим EOF == 0xFF

                          А если собирать под ARM, то бесконечный цикл (char == unsigned char, unsigned char != -1).

                          0
                          Байт 0xFF для Windows-1251 это буква я.
                          Вот так легко и просто можно написать программу, не умеющую некоторые буквы в некоторых языках. Как старинный софт для FIDO, не умеющий букву Н ;)
                            +2
                            Вспомнилось «На FTP сервере окончательно исправлена проблема с буквой '' теперь вы можете заливать файлы с названими с буквой ''»
                              +2
                              И что-то такое (с буквой «я») совершенно точно попадалось, кажется, у Borland C++ с ней были проблемы.
                                0

                                Telnet в кои8 иногда рвал соединениЯ, если в стриме попадалась буква Я. Маялись админы русскоязычных мадов, в частности "Мир Мерлина". Да, вероятно, проблема на стороне программирования лежала именно в слепом конвертировании getc() в signed char, скажем. Но пользователям видно по-другому, я тогда больше играл, чем кодил.

                            +15
                            Просто стыдно читать, с каким пафосом автор пишет о том, чего не знает, не удосужившись прочеть даже викпедию!
                            Да, EOF *БЫЛ* символом конца файла, в DOS этот символ был необязательным, но поддерживался, а в CP/M, например, это вообще — единственный способ обозначения конца файла.
                              +6

                              Неверные итоги.


                              1. EOF = 0x1a (упоминалось выше в комментах), вполне существующий символ. И почему это вы его в ASCII-таблице не нашли? Update: а, его переименовали с 199х — значит "был" такой символ. В сохранившейся у меня книжке Programming for MS-DOS символ 0x1a всё ещё назывался EOF.
                              2. Верно для текущей эпохи, в которой верно ещё и 3), но в общем случае неверно. DOS 5.0 (как минимум) при попытке сделать type somefile.wav, где файл — валидный WAV тех времен, выдавал на дисплей "Creative voice file" и затыкался. Побайтный анализ показывал, что после данной строки в бинарном файле шли два символа EOF, за которыми уже начинался заголовок бинарного сегмента файла. Тот же трюк использовался во многих других программах, включая, не в последнюю очередь, игру GEEKWAD, сообщавшую "хакеру" информацию "The secret codeword is CHEAT", каковое слово приводило к реакции а-ля IDDQD в Heretic'e.
                              3. Сейчас — верно, но не только оно.
                              4. Был такой символ. Сейчас его нет, и EOF теперь состояние потока.
                                +3
                                Соглашусь. Особенно доставляют например вот такие «доказательства»:

                                >Для этого можно воспользоваться командой xxd:
                                Чем, простите? Прежде чем результаты команды принимать за доказательство чего-либо, нужно сначала показать, каким именно API пользуется эта команда. Кроме того, тот факт, что мы не можем прочитать этот символ из файла, вообще не означает, что этого символа нет в файле (в блоке на диске). Чтобы доказать это, нужно как минимум прочитать дисковый блок.
                                  +1
                                  > приводило к реакции а-ля IDDQD в Heretic'e

                                  Немедленное самоубийство?
                                    0

                                    В doom же

                                      +1

                                      Гугл подсказывает, что всё же как в Heretic'е.


                                      Heretic:


                                      iddqd. Kills the player. Originally the Godmode cheat in Doom, it is a joke by the developers by making it have the opposite effect in Heretic. When entered, on the screen is displayed: "Trying to cheat, eh? Now you die!"

                                      Geekwad:


                                      No Fair Cheating: If you input CHEAT as a password, Cybergeek gets furious and makes the ship explode
                                    0
                                    Помню в начале 2000-х (3-4 года) за этот символ (или два, точно не помню — давно было) в PE-экзешники дописывали трек номер — чтобы потом читать его при запуске программы и отправлять на сервак для статистики — какая реклама (сайт) лучше работает для распространения. Сначала читали как бинарный файл, но позже были проблемы (уже в 2000 или xp) — считать сам себя экзешник не мог — поэтому открывали его через CreateProcessA и шагали по страницам памяти за переделы — все работало. Поэтому в «штатном» режиме чтения EOF всегда считал состоянием потока — то есть курсор чтения файла вышел за границы размера файла, и проверял это до чтения файла — достигнут ли конец файла и потом пробовал считать данные. Собственно как и константа INVALID_HANDLE_VALUE в винде по умолчанию -1, потому что handle принято считать всегда больше или равным 0, но меньше или равным максимальной разрядности, то есть те самые FF, собственно как и коды символов. А сравниваемые значения всегда приводятся к большей разрядности и получаем, что -1 никогда не будет в диапазоне 0..ff, что удобно при использовании кодов ошибок. По такой же схеме INVALID_HANDLE_VALUE равный -1 не попадающий в 0..0xFF FF FF FF. Это если про символы — но тут холивар разводить можно долго про «символ» vs «признак окончания чтения потока данных». Смотря в каком режиме и контексте используется данная аббревиатура…
                                      +3
                                      В командной строке Windows выполняем:
                                      >echo «line1» >test1.txt
                                      >echo «line2» >test2.txt
                                      >copy test1.txt + test2.txt > test3.txt
                                      И смотрим test3.txt в HEX редакторе — последний символ в файле — 0x1A

                                      Так что был такой символ, точно был. Даже вот такие рудименты от него остались.
                                        +1

                                        Вау! Сто лет не видел использования copy file1+file2, а тут ещё такой сюрприз. И таки да, WS2012 — confirmed.

                                          +1
                                          да, только я накосячил с перенаправлением.
                                          Правильный вид третьей команды — вот такой
                                          copy test1.txt + test2.txt test3.txt
                                          там пробел должен быть а не правая угловая скобка.
                                          Прошу прощения у всех, у кого фокус не получился
                                            0

                                            этот фокус не получился и с пробелом

                                        0
                                        стандарт С11, стр.296

                                        7.21.1
                                        The macros are…
                                        EOF
                                        which expands to an integer constant expression, with type int and a negative value, that
                                        is returned by several functions to indicate end-of-file, that is, no more input from a
                                        stream;

                                        и выше, на той же странице, в пункте 2, касательно типа FILE

                                        end-of-file
                                        indicator that records whether the end of the file has been reached

                                          0
                                          Недавно я читал книгу «Компьютерные системы: архитектура и программирование. Взгляд программиста». Там, в главе про систему ввода-вывода Unix, авторы упомянули о том, что в конце файла нет особого символа EOF.


                                          Ясно, что перевод/копипаст, но хотябы не поленились найти эту книгу, упомянутую главу, и бросить пруф на место, где «авторы упомянули о том, что в конце файла нет особого символа EOF.»

                                          PS: а был еще EOL, ну там то точно символ, даже два можно!
                                            +1
                                            Девиз автора статьи:
                                            «Все, что стоит делать, стоит делать плохо — пока ты не научишься делать это хорошо».
                                            “Anything worth doing is worth doing poorly — until you learn to do it well.”

                                            ruslanspivak.com/pages/about
                                              +7
                                              Автор сумел разжечь холивар на пустом месте в буквальном смысле этого слова.
                                              Талантище.
                                              Респектище.
                                              PS. Напомнило исследование — самая короткая программа, которая завесит DOS. Оказалось — 0 байт.
                                                +5
                                                Тут, опять же, можно проверить коды символов в таблице ASCII, можно взглянуть на таблицу Unicode и узнать о том, в каком диапазоне могут находиться коды символов. Мы же поступим иначе: запустим интерпретатор Python и ...

                                                На серьёзных щах гонят какую-то дичь с доказательствами от Васи из 7 класса.

                                                  –2
                                                  А еще есть BOF и как бы понятно, что BOF и EOF не символы, а признаки

                                                  docs.microsoft.com/ru-ru/sql/ado/reference/ado-api/bof-eof-properties-ado?view=sql-server-ver15

                                                  Тем, кто работал с файлами баз данных типа dbf, это давно известно
                                                    0
                                                    А есть ещё BOM. И это символ, но к статье это не имеет отношения.
                                                    +1
                                                    Интересный факт: в ДОСе после копирования со слиянием текстовых файлов командой
                                                    copy Файл1.txt + Файл2.txt + Файл3.txt Файл123.txt в конец файла добавлялся загадочный символ: "→". Не он ли это был? :-)
                                                      0
                                                      он самый, см. мой коммент выше
                                                      0
                                                      EOF это пережиток тех времен, когда файлы считывались последовательно, символ за символом, с ленты. После появления файловых систем на дисках необходимости в нем нет, а след в API остался.
                                                        0
                                                        EOF это символ таблицы ASCII с кодом 0x1A (26 десятичный)
                                                        А как оно там в каких библиотеках обрабатывается — дело десятое. Их назначение как раз в том чтобы скрыть детали реализации абстракции. В конце концов таблица ASCII тоже не более чем случайная последовательность принятая в определенных протоколах для кодирования инфы. А понятие конца файла как бе универсально а посему на уровне либ от такой частности как используемая таблица кодировки зависеть не должно от слова совсем.
                                                          +1
                                                          Эти управляющие символы ведут свои корни ещё с телетайпов и др. полумеханических машин. Коли утверждать чего нет, а чего есть надо бы посмотреть старые документы ;)
                                                          Собсна символ 26, он же 0х1A назывался (eof) © Microsoft 1985-1990
                                                          image
                                                          Т.к. абсолютное большинство ЭВМ снабжено осью от МС, то и символ правильно называть еоф, а не суб.
                                                            0
                                                            stackoverflow.com/questions/13582804/why-can-windows-not-read-beyond-the-0x1a-eof-character-but-unix-can

                                                            В некоторых программах которые до сих пор существуют есть такая фича
                                                              0

                                                              EOF — это непечатный непечатаемый символ.


                                                              P.S. Эпоха хайп-статей апофигевающих от непонятных нюансов в стандартах. Ждем статьи про то, что "перевод строки это не символ, но под виндой всё не так просто"

                                                                0
                                                                В современных *nix символ ASCII EOF(0x1A) игнорируется чуть более чем полностью. Собственно и сам символ EOF не нужен, от слова совсем.
                                                                image
                                                                И вообще, причём тут DOS / Windows / CP/M / RSX-11/ whatever? Статья про UNIX/Linux, а не вот это вот всё.
                                                                0
                                                                C:\> copy con 1.txt
                                                                blah
                                                                blah-blah
                                                                (<Ctrl-Z>|<Alt+026>)
                                                                1 file(s) copied
                                                                C:\>

                                                                У кого есть под рукой, на FreeDOS прокатывает?

                                                                UPD: На PC-DOS работает:
                                                                image
                                                                  0

                                                                  сишники странные…
                                                                  Когда я изучал Паскаль 7, где-то вычитал, что EOF это ПРИЗНАК конца файла и я всегда eof воспринимал как флаг окончания получения данных. Если сравнить с потоком, то истинное условие равенства позиции и длины файла.
                                                                  Как байт в конце файлов его не встречал и никогда не размышлял над этой глупостью.

                                                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                  Самое читаемое