Форум программистов, компьютерный форум, киберфорум
C (Си)
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
4 / 5 / 0
Регистрация: 14.06.2020
Сообщений: 121

Корректное определение конца бинарного файла

30.03.2026, 10:09. Показов 5149. Ответов 60

Студворк — интернет-сервис помощи студентам
Доброго дня, коллеги.
Понял, что практически не работал с "сырыми" бинарниками, в основном писал/читал структурки и поля известной длины, а по файлу перемещался с помощью fseek(). Поэтому никогда не возникало необходимости в детектировании конца файла. В общем, время пришло...

Обычно читаю вот этим (знаю что неоптимальна):
C
1
2
3
4
5
6
7
8
bool _readfile(FILE *F, unsigned char *data, size_t datasize)
{
   // Проверяем указатели
   if(F == NULL || data == NULL) return false;
   // Читаем данные
   for(size_t rdd = 0; rdd < datasize;) rdd += fread(data + rdd, 1 ,datasize - rdd, F);
   return true;           
};
Для использования feof(), как я понял, сгодится такая модификация:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
bool t_readfile(FILE *F, unsigned char *data, size_t *datasize)
{
    // Проверяем указатели
    if(F == NULL || data == NULL || datasize == NULL) return false;
    // Проверяем достижение конца файла до запуска цикла
    int eof_check = feof(F);
    if(eof_check > 0 || eof_check == EOF) return false;
    // Читаем данные
    for(size_t toread = *datasize, readed = 0; readed < toread;)
    {
        // Читаем как получается
        readed += fread(data + readed, 1 ,toread - readed, F);
        // Проверка конца файла
        eof_check = feof(F);
        if(eof_check > 0 || eof_check == EOF)
        {
            // Передаем сколько прочитано и ломаемся
            *datasize = readed;
            break;
        }
    }
    return true;
};
Модификация сгодится или нужно что-то другое?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
30.03.2026, 10:09
Ответы с готовыми решениями:

Не корректное исполнение бинарного кода
Добрый день дорогие форумчане. На днях столкнулся с такой проблемой как некорректное открытие...

Создание бинарного дерева из бинарного файла
struct Bin { string name; string city; int players; int score; }; void...

Создание бинарного дерево из бинарного файла
struct Bin { string name; string city; int players; int score; }; void...

60
Нарушитель
447 / 888 / 106
Регистрация: 23.11.2021
Сообщений: 5,211
Записей в блоге: 19
03.04.2026, 21:04
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от 000d60 Посмотреть сообщение
Тогда зачем так уверенно утверждать что то?
А кто я буду, если не буду уверенно что-то утверждать, даже если в этом вообще не разбираюсь? ☺
Цитата Сообщение от 000d60 Посмотреть сообщение
У тебя не грузится - не значит не рабочий
У меня не грузится - значит, и у большинства россиян не грузится! "Ростелеком" - штука зело весомая, по всей России свои когти распустил…
0
4 / 5 / 0
Регистрация: 14.06.2020
Сообщений: 121
03.04.2026, 22:10  [ТС]
Цитата Сообщение от 000d60 Посмотреть сообщение
Есть контракт : https://en.cppreference.com/w/c/io/fread.html
И пример основан на этом же источнике.
Вот! Прямо то что доктор прописал. Теперь мне понятно что и как применять. Моя благодарность за раскрытие темы сисек fread()
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13233 / 6865 / 1827
Регистрация: 18.10.2014
Сообщений: 17,398
04.04.2026, 08:01
Цитата Сообщение от Eddy_Em Посмотреть сообщение
Тут вообще не понимаю: какие могут быть ожидания? В файл записали 5 байт, а потом считали 5 байт. Естественно, будет конец файла...
А вот сколько дылдонили в каждой методичике и в каждом FAQ, что в те времена, когда разрабатывалась стандартная библиотека языка С, в примитивных юниксоидных ОС и соответствующих им по примитивности файловых системах не существовало понятия "размера файла" вообще. Поэтому "записали 5 байт, а потом считали 5 байт" в вводе-выводе того времени не значило вообще ничего. Никакого конца файла в такой ситуации речи быть не может в принципе. До развития корней современной Windows и соответствующих файловых систем были еще годы и годы, а до того, как это развитие будет перекопировано в юникс - еще больше.

Так что понятия "стоять не конце файла" в стандартной библиотеке С нет в принцупе. Есть только понятие "въехать с разгона в маркер конца файла" (на магнитной ленте или перфоленте). Но для этого "записали 5 байт, а потом считали 5 байт" мало - слишком рано остановились.
0
 Аватар для peter_irich
371 / 227 / 53
Регистрация: 18.10.2017
Сообщений: 2,437
04.04.2026, 10:51
TheCalligrapher, так вопрос был задан сейчас, когда размер файла известен. И что же, во всяких ранних fat он не был известен?
Вопрос был по работе с бинарным файлом, так в чём преимущество fread() перед read() и lseek()? лично я fread() не пользовался.
0
Нарушитель
10899 / 5833 / 1289
Регистрация: 12.03.2015
Сообщений: 26,921
04.04.2026, 11:49
Цитата Сообщение от Hexpitlel Посмотреть сообщение
Verevkin, Вариант с fseek() - тоже вариант, я о нем знаю, но вся эта последовательность "открыть, перейти в конец, взять значение, закрыть" у меня вызывает отвращение. Но рабочий вариант, безусловно.
Это ж пример! Подразумевается: открыть, перейти в конец, взять значение, перейти в начало, обработать все данные (с учётом размера), закрыть
0
Нарушитель
447 / 888 / 106
Регистрация: 23.11.2021
Сообщений: 5,211
Записей в блоге: 19
04.04.2026, 13:16
А чем вам fstat не нравится для получения размера файла?
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13233 / 6865 / 1827
Регистрация: 18.10.2014
Сообщений: 17,398
04.04.2026, 16:15
Цитата Сообщение от peter_irich Посмотреть сообщение
так вопрос был задан сейчас, когда размер файла известен. И что же, во всяких ранних fat он не был известен?
Поточный ввод-вывод в С ориентирован изначально именно на потоки, то есть устройства последовательного доступа, то есть фактически на стример на магнитной ленте, в котором реализация любой FAT по очевидным причинам - весьма нетривиальная задача. В ранних же FAT для устройств произвольного доступа размер файла был известен в лучшем случае с точностью до некоего условного "сектора", а точный конец файла в рамках последнего сектора можно было распознать только путем чтения специального маркера. Остальное я писал выше, повторяться не буду.

Цитата Сообщение от peter_irich Посмотреть сообщение
Вопрос был по работе с бинарным файлом, так в чём преимущество fread() перед read() и lseek()?
Я давал подробный ответ в сообщении #10.

Нестандартная функция read сама по себе пригодна только для чтения 1 байта. Если вам нужно прочитать более одного байта при помощи read, то вам придется принимать во внимание возможность spurious underread, то есть на основе read вручную писать fread. Возникает очевидный вопрос: зачем вручную писать fread, если он уже есть в стандартной библиотеке?

Кстати, вся эта тема началась с того, что ТС зачем-то вздумал написать fread на основе fread ... Функции _readfile и t_readfile - это именно попытки продолжить чтение после spurious underread, в то время как у fread не бывает (!) spurious underread. Для того функция fread и создана, чтобы решить этот вопрос. Скорее всего ТС где-то начитался про особенности read, но почему-то "перенес" их на fread и принялся взахлеб решать несуществующую проблему.

Цитата Сообщение от peter_irich Посмотреть сообщение
лично я fread() не пользовался
Мыши, кактус, овнокод...
0
 Аватар для peter_irich
371 / 227 / 53
Регистрация: 18.10.2017
Сообщений: 2,437
04.04.2026, 18:56
TheCalligrapher, вы, похоже, имеете в виду какую-то особенную, свою собственную read(). т.к. при вызове настоящей read() указывается, сколько байтов она должна прочитать, а она сообщает, сколько прочитала. Как это в ней реализовано, программиста не касается.
1
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13233 / 6865 / 1827
Регистрация: 18.10.2014
Сообщений: 17,398
04.04.2026, 19:35
Цитата Сообщение от peter_irich Посмотреть сообщение
вы, похоже, имеете в виду какую-то особенную, свою собственную read(). т.к. при вызове настоящей read() указывается, сколько байтов она должна прочитать,
Нет, фукция read никому ничего не должна. Сколько же можно дылдонить то, что описано и переописано уже вдоль и поперек в каждом FAQ по функции read:

Функция read не "должна" читать столько данных, сколько вы попросили. Функция read имеет право прочитать меньше данных, чем вы попросили, без каких либо обоснований и без объяснения причин вообще. Функция read лишь гарантирует вам, что если поток находится в нормальном состоянии (не EOF, не ошибка I/O), то ею будет прочитан как минимум один байт информации. Другими словами, функции read в общем случае глубоко плевать, что вы там указали на тему "сколько байтов она должна прочитать" (смешно). Она должна прочитать лишь один байт, а больше она вам ничего не должна. Будет ли она читать больше одного байта за вызов - по ее желанию, зависит от погоды на Марсе.

Поэтому в своем коде голую функцию read вы можете применять только для чтения одного байта. А если вам нужно прочитать больше - вам придется писать ручками надстройку над функцией read в виде цикла, который будет анализировать возвращаемое значение read и вызывать функцию read снова, снова и снова, пока не будет вычитан нужный вам объем данных (возможно - по одному байту, если функции read так заблагорассудится).

Если у вас в коде стоит вызов функции read для чтения блока данных (размера больше 1) без цикла вокруг нее - это сразу грубейшая ошибка. Вот именно для того, чтобы вам не нужно было писать снова и снова эти циклы, и создана функция fread, которая уже содержит внутри такой цикл. Функция fread предназначена для того, чтобы решить проблему "безосновательного отказа" читать данные, свойственную функции read.

Цитата Сообщение от peter_irich Посмотреть сообщение
а она сообщает, сколько прочитала.
Вот для этого read и "сообщает, сколько прочитала" - чтобы вы проверили это значение и циклически повторили запрос, пока не получите все нужные вам данные.
1
Нарушитель
447 / 888 / 106
Регистрация: 23.11.2021
Сообщений: 5,211
Записей в блоге: 19
04.04.2026, 21:49
peter_irich, исключительно ее и пользую. Вот для write в сокет уже поаккутатней нужно быть: либо send использовать, либо о SIGPIPE позаботиться. Но в общих случаях, если заранее всë нужное сделал, нет смысла париться. У меня общие функции в библиотеке как для чтения из файлов, так и из сокетов: просто read. Аналогично с записью: просто write. Я пользуюсь своей буферизацией. А буферизацию glibc использую лишь для всяких printf'ов в stderr, stdout, да в лог-файлы (которые открываются на момент записи, блокируются, туда пишется содержимое, файл разбокируется и закрывается)…
У маздайщиков, думаю, совершенно другой подход. Но мне вообще на них наплевать: это же совершенно иная вселенная, перпендикулярная реальности!
0
 Аватар для peter_irich
371 / 227 / 53
Регистрация: 18.10.2017
Сообщений: 2,437
04.04.2026, 22:20
TheCalligrapher, всё-таки похоже, что у вас особeнная read(). Я всегда читал ею столько байтов, сколько указано в её вызове, с проверкой, сколько считано. При чтении больших файлов размер порции обычно указывал 4096 байтов, да, в этом случае витал в цикле. Никаких проблем никогда не было.
ВСопрос был, как найти конец файла. Для этого не надо его читать, м ожно воспользоваться lseek().
0
Нарушитель
447 / 888 / 106
Регистрация: 23.11.2021
Сообщений: 5,211
Записей в блоге: 19
04.04.2026, 22:31
Цитата Сообщение от peter_irich Посмотреть сообщение
Для этого не надо его читать, м ожно воспользоваться lseek().
Еще раз вопрос: зачем? Есть же для этого функция fstat! Ну или прочие из того же семейства.
Если же файл "на ходу" обновляется, то это - всегда проблемы. И хорошо, если лишь один пишет, а многие - читают… Но и здесь есть такая штука, как flock. Да хоть в /dev/shm семафор заведи!..
В любом случае, read вернет считанное количество байт, либо -1 в случае ошибки (а ее легко можно понять по состоянию errno: или еще раз попытаться, или сокета больше нет).
0
 Аватар для peter_irich
371 / 227 / 53
Регистрация: 18.10.2017
Сообщений: 2,437
04.04.2026, 23:12
Eddy_Em, так там вроде бы требовалось найти конец файла, т.е. встать на него
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13233 / 6865 / 1827
Регистрация: 18.10.2014
Сообщений: 17,398
04.04.2026, 23:13
Цитата Сообщение от peter_irich Посмотреть сообщение
всё-таки похоже, что у вас особeнная read(). Я всегда читал ею столько байтов, сколько указано в её вызове, с проверкой, сколько считано. При чтении больших файлов размер порции обычно указывал 4096 байтов, да, в этом случае витал в цикле. Никаких проблем никогда не было.
Я вас поздравляю, но это - не более чем разглагольствования из области "я всегда забивал шурупы молотком и нормуль - все держалось". Никто же не отрицает что овнокод может работать... А не сработает - запустим еще раз, вдруг в этот раз сработает, правда?

Тем не менее, когда вы пользуетесь чужим API, то писать код вы должны на основе спецификации этого API, а не на основе "я всегда делал так-то все работало...". Читайте POSIX спецификацию функции read, там все написано. (Не вижу причин повторяться. Однако подозреваю, что в рамках ваших представлений, у меня практически все "особенное": и POSIX, и функция read, и язык С, и все остальное ¯\_(ツ)_/¯ )

---

P.S. Разумеется, функция read не будет заниматься умышленным вредительством и не будет специально вам назло читать данные по одному байту. Разумеется, функция read постарается выполнить ваш запрос целиком. Но тем не менее спецификация Linux syscall read говорит вам, что выполнение read может быть прервано в любой момент, по любой причине, без видимых для вас причин, без объяснения причин. Те, кто знаком с низкоуровневым программированием в многозадачных системах, прекрасно знакомы с причинами и множественными примерами такого spurious поведения. Это совершенно нормально и привычно.
0
Заблокирован
04.04.2026, 23:39
Два линуксоида, курильщика мануалов, а "вкурить" не могут...
https://man7.org/linux/man-pages/man2/read.2.html
It is not an error if this number is smaller than the number of
bytes requested; this may happen for example because fewer bytes
are actually available right now (maybe because we were close to
end-of-file, or because we are reading from a pipe, or from a
terminal), or because read() was interrupted by a signal. See
also NOTES.
https://pubs.opengroup.org/onl... /read.html
The value returned may be less than nbyte if the number of bytes left in the file is less than nbyte, if the read() request was interrupted by a signal, or if the file is a pipe or FIFO or special file and has fewer than nbyte bytes immediately available for reading.
If a read() is interrupted by a signal after it has successfully read some data, it shall return the number of bytes read.
0
 Аватар для peter_irich
371 / 227 / 53
Регистрация: 18.10.2017
Сообщений: 2,437
05.04.2026, 08:29
000d60, благодарю за просвещение, но мне никогда не приходилось читать socket или pipe, я читал только обычные файлы.
Вернее, я читал данные с сокетов, в Qt с помощью их функции readAll(), в терминале по UDP сейчaс не помню, как, а для записи, сейчас посмотрел, там sendto(), для чтения recfrom()..
0
 Аватар для volodin661
7153 / 2341 / 353
Регистрация: 10.12.2013
Сообщений: 8,123
05.04.2026, 14:01
Цитата Сообщение от peter_irich Посмотреть сообщение
там вроде бы требовалось найти конец файла, т.е. встать на него
если долго стоять на конце файла, он может распухнуть ( не конец, а файл ) по причине возможного доступа на запись из другого процесса.
0
4 / 5 / 0
Регистрация: 14.06.2020
Сообщений: 121
05.04.2026, 14:33  [ТС]
TheCalligrapher, ваши посты действительно интересно и познавательно читать. Осознаю, что я выгляжу ребенком в песочнице с высоты ваших знаний и опыта. Беру свои слова обратно про кислоту.

Может порекомендуете хорошую книгу на русском языке в которой не просто описываются все эти исторические особенности низкоуровневого поведения функций ввода-вывода, а объясняются причинно-следственные связи и сопутствующие решения. Очень интересно погрузиться в эту тему.
п.с. с английским, увы, беда.
0
 Аватар для peter_irich
371 / 227 / 53
Регистрация: 18.10.2017
Сообщений: 2,437
10.04.2026, 12:47
Есть переводная книжка на русском "Программирование для Linux. Профессиональный подход". Там три автора, 1-й в списке Кларк Митчелл.
Ещё "Разработка приложений в среде Linux", Майкл К. Джонсон, Эрик В. Троан.
1
4 / 5 / 0
Регистрация: 14.06.2020
Сообщений: 121
12.04.2026, 13:29  [ТС]
peter_irich, спасибо
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
12.04.2026, 13:29

Рекурсивная функция, которая выведет массив с конца (переворачивать массив не нужно, просто вывод элементов с конца)
Рекурсивная функция, которая выведет массив с конца (переворачивать массив не нужно, просто вывод...

Определение конца файла
помогите пожалуйста определить условие конца файла #include &lt;iostream&gt; #include &lt;cstdio&gt;...

определение конца файла
При чтении не получается выйти из цикла с помощью istream::eof(), было много вариантов причины...

Определение конца файла
Возникают проблемы при чтении бинарного файла, а именно цикл осуществляет лишнюю итерацию и тем...

Определение конца файла , файл задан классом string
Я хочу осуществить чтение файла с обработкой и записью в другой файл. Для этого я хочу использовать...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
Запустил конкурс "тем и промптов для текстовых квестов созданных почти чисто ИИ"
Adler 06.10.2026
Всем привет! За последние три-четыре дня я создал более 16 текстовых квестовых игр используя преимущественно по одному запросу к ИИ на игру. Мне так понравилось смотреть все ветки/ сцены во всех. . .
ИИ не может найти нужный язык в списке
Supersumestria 05.10.2026
Я ему даю вот такое изображение и прошу найти и подчеркнуть немецкий язык. Возвращает он вот это: https:/ / i. **********/ vqBWLe2. png Нужную строчку в 3й колонке просто выдумал. . Это. . .
Новая последняя моя музыка в SUNO
zorxor 05.10.2026
Здравствуйте, дорогие мои друзья! С большой радостью я хотел бы представить вам свою новую последнею музыку, которую сгенерировала мне по моей просьбе нейросеть SUNO. С уважением, zorxor. Это. . .
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru