Функция fread читает а функция fwrite пишет в файл данные начиная с позиции

Обновлено: 07.07.2024

Пример взял с сайта для изучения C++. При записи в файл в нем самом отображается ерунда, но не то, что надо. С чего бы это?

50.1k 9 9 золотых знаков 96 96 серебряных знаков 288 288 бронзовых знаков 109 1 1 золотой знак 3 3 серебряных знака 11 11 бронзовых знаков

fread/fwrite функции читают/пишут данные в бинарном формате. Если хочется человеко-читаемый (текстовый) формат, то можно использовать fscanf/fprintf вместо fread/fwrite соответственно.

Приведённый в вопросе код должен работать как есть.

Что конкретно fwrite запишет на диск, может зависеть от платформы (размер типа (LLP64, LP64 модели), порядок байтов, и даже побитовое представление типов (дополнительный код, обратный код), выравнивание типов).

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

На моей машине test файл содержит:

Первая колонка, нумерует байты, в каждой строке по 16 байт, представленных командой xxd ввиде шестнадцатеричных чисел (каждые две цифры соответствуют одному байту). Самая правая колонка показывает печатаемые байты (точка используется для непечатаемых в ascii символов).

Вот байты соответствующие каждому значению:

Можно сразу сказать, что int является 32-битным типом (4 байта, предполагая 1 байт = 8 бит), а long 64-битным типом (что верно для lp64 модели) с порядком байтов от младшего с старшему (little-endian) на моей машине.

Если записать байты для i и l в порядке от старшего к младшему (big-endian) как обычно числа записаны на бумаге пишут:

  • int i 00000065 в шестнадцатеричной системе соответствует 101 в десятичной системе(6516 = 10110), что является корректным значением для i
  • long l 000000000001e08f в шестнадцатеричной системе соответствует 123023 в десятичной системе (1e08f16 = 12302310), что также верно.

Число d записано как число двойной точности в IEEE 754 формате --
d = ±знак · (1 + мантисса / 2 52 ) · 2 порядок − 1023 :

(cнова переписал байты от старшего к младшему) Или в двоичной системе -- все 64 бита числа d :

Самый левый бит это знак, в данном случае он 0 , то есть d является положительным, затем 11 бит порядок = 100000000102 = 102610, оставшиеся 52 бита мантисса:

1000011101011100001010001111010111000010100011110112
= 238127830297215010
= 875c28f5c28f616

d = (1 + 2381278302972150 / 2 52 ) · 2 1026 − 1023
= 3442438965171323 / 281474976710656
= 12.23

Бинарные файлы, чтение и запись
Доброго времени суток. Подскажите пожалуйста, как организовать побайтовое чтение и запись данных в.


Запись / чтение из файла через fwrite/fread
Итак здравствуйте) объясниет пожалуйста что за баг))) простенькая вроде программа. записываем.

Функции fread() и fwrite()
Меня интересует что это за "счётчик" в этих функциях fwrite( massiv, *size_int * sizeof(unsigned.

Размер указателя может отличаться от размера типа, там мог бы быть sizeof(float*).
Однако, запись указателя в файл — вообще малополезное занятие, актуальными значения будут только в пределах одного запуска программы. Запись и чтение просиходит на РАЗНЫХ комьютерах. А как запись значения из указателя. Я думаю, проблема в том, что под указателем нет памяти и он ни на что не указывает, поэтому в файл пишите мусор. Он у вас на что должен указывать?

НУ на флот переменную, дескрпитор, прохожу в режиме дебага в переменной значения есть.

Добавлено через 10 минут

Я думаю, проблема в том, что под указателем нет памяти и он ни на что не указывает, поэтому в файл пишите мусор. Он у вас на что должен указывать? Спасибо ваш коментарйи наталкнлу на мысыль. В общем решил проблему так:

Это все очень криво. Не видно как объекты класса создаются. Если поле класса указатель, то под него, в конструкторе, память обычно выделяется. А если память выделена, то в неё уже можно читать из файла, а не создавать дополнительную переменную, адрес которой присваивается полю-указателю.

Добавлено через 3 минуты
Это код только для проверки (как приблизительно должно выглядеть):

Добавлено через 3 минуты
Это код только для проверки (как приблизительно должно выглядеть):

Спасибо так и реализовал, вывод не пускайте джавистов к с++ разработке)

Но тут не всё так просто. Нужно предусмотреть освобождение памяти под указателем в деструкторе, и сделать явные конструкторы копирования и присваивания (для глубокого копирования/присваивания). Иначе будут проблемы.

А подскажите ещё такой момент, как правильно сделать поиск-замену по файлу.
Есть у меня некая структура, я по циклу перебираю записи в файле, нахожу необходимую, меняю значения переменных в структуре и записываю на то-же место в файле, но происходит что-то не то.

Что я хотел бы знать.

если это положить в цикл, будет оно каждый последующий блок менять? Для перемещения курсора не применяйте -sizeof(). Вот так попробуйте:
Для перемещения курсора не применяйте -sizeof(). Вот так попробуйте:
Спасибо, похоже именно в этом и была ошибка, вроде заработало как надо. Просто sizeof() возвращает число без знака и компилятор не хочет ему минус приделывать. Получается перемещение не назад, а вперёд. Однако что-то всё-равно не так, происходит что-то непонятное.
Такое впечатление что fwrite не перезаписывает данные, а вставляет в ту позицию куда был установлен fseek, причем длина файла не меняется.

Как видите это всё?

Добавлено через 1 минуту
После записи делайте:

Как видите это всё?

Добавлено через 1 минуту
После записи делайте:

И снова в точку! Я в процессе работы программы следил за выходным файлом, после fwrite там ничего не менялось, менялось только после fclose.
Таким же макаром я с 'cin' бился, пока flush не применил))

Fread,fopen,fwrite
Добрый день, пытаюсь считать бинарно данные из файла с помощью fread, а далее записать в другой.

Fread() & fwrite()
Помогите пожалуйста ,не могу понять как использовать функции fread() и fwrite(). И если можно.


Fread/fwrite size vs count
Есть ли практическая разница между указанием полного размера только в size или же в size*count.


Аналог С функции fread и fwrite в С++
Здравствуйте, какие есть аналоги функций fread() fwrite в С++?

Двоичный файл это последовательность данных не текстового формата. Поэтому редактировать файл в текстовом редакторе невозможно. С другой стороны такой файл может иметь меньший объем, а для редактирования могут быть предназначены специальные редакторы.

Чтение и запись потока байтов выполняют функции fread и fwrite .

fread(void *buffer, size, count, FILE *f);

Функция считывает count элементов длиной size байтов в буфер, заданный указателем buffer , из потока f .

Функция возвращает количество прочитанных элементов, которое может быть меньше count , если при чтении произошла ошибка или встретился конец файла.

fwrite(const void *p, size, n, FILE *f);

Функция записывает n элементов длиной size байт из буфера, заданного указателем р, в поток f . Возвращает число записанных элементов.

Пример, демонстрирующий работу с этими функциями:

struct Client

char SurName[27];

char Name[21];

char SecName[21];

FILE *stream;

Client AClient , RClient ;

//Открываем файл для вывода

AClient.Num = 1;

strcpy(AClient.SurName,"Petrov");

strcpy(AClient.Name, "Petr");

strcpy(AClient.SecName, "Petrovich");

// Запись структуры в файл

fwrite(&AClient, sizeof(AClient), 1, stream);

//Закрываем файл

fclose ( stream ) ;

//Открываем файл для чтения

fread(&RClient, sizeof (RClient) , 1 , stream) ;

//Закрываем файл

fclose (stream) ;

printf ("Num = %d SurName = %s Name = %s SecName = %s",

RClient . Num , RClient . SurName , RClient . Name , RClient . SecName ) ;

В этом примере вначале файл открывается для записи в него значений полей из структуры AClient , затем этот файл открывается для чтения содержащейся в нем информации в структуру RClient . После чего поля этой структуры выводятся на экран. При выполнении программа выводит на экран:

The structure contains:

Num = 1 SurName = Petrov Name = Petr SecName = Petrovich

Функции позиционирования

Операции ввода/вывода выполняются, начиная с текущей позиции потока, определяемой положением (значением) указателя потока. Указатель устанавливается при открытии на начало или конец файла (в соответствии с режимом открытия ² a ² , ² a + ² ) и изменяется автоматически после каждой операции ввода/вывода. Текущее положение указателя можно получить с помощью функций ftell и fgetpos и задать явным образом с помощью функций fseek , fsetpos и rewind . Эти функции нельзя использовать для стандартных потоков.

long int ftell ( FILE * f );

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

int fgetpos ( FILE * f , fpos _ t * pos );

Функция возвращает текущую позицию в файле, связанном с потоком f , и копирует значение по адресу pos . Это значение позднее может использоваться функцией fsetpos . Возвращаемое значение имеет тип fpos _ t .

int fseek(FILE *f, long off, int org);

Функция перемещает текущую позицию в файле, связанном с потоком f , на позицию off , отсчитываемую от значения org , которое должно быть равно одной из трех констант, определенных в < stdio . h >:

SEEK _ CUR ( =1 ) – от текущей позиции указателя;

SEEK _ END ( =2 ) – от конца файла;

SEEK _ SET ( =0 ) – от начала файла.

Функция возвращает 0 , если указатель текущей позиции в файле успешно изменен, и отличное от 0 значение в противном случае.

int fsetpos(FILE *f, const fpos_t *pos);

Функция перемещает текущую позицию в файле, связанном с потоком f , на позицию * pos , предварительно полученную с помощью функции fgetpos .

void rewind ( FILE * f );

Функция очищает флаги ошибок в потоке f и устанавливает текущую позицию на начало файла.

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

Рассмотрим пример, демонстрирующий работу этих функций:

struct Client

char SurName[27];

char Name[21];

char SecName[21];

FILE *stream;

Client AClient , RClient ;

//Открываем файл для вывода

AClient.Num = 1;

strcpy(AClient.SurName,"Petrov");

strcpy(AClient.Name, "Petr");

strcpy(AClient.SecName, "Petrovich");

// Запись структуры в файл

fwrite(&AClient, sizeof(AClient), 1, stream);

long int pos = ftell(stream);

//Выводим позицию файла и длину структуры

//Репозиционируем файл

rewind ( stream );

//Открываем файл для чтения

fread(&RClient, sizeof (RClient) , 1 , stream) ;

//Закрываем файл

fclose (stream) ;

printf ("Num = %d SurName = %s Name = %s SecName = %s",

RClient . Num , RClient . SurName , RClient . Name , RClient . SecName ) ;

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

The file pos = 76 structure length = 76

The structure contains:

Num = 1 SurName = Petrov Name = Petr SecName = Petrovich

Пример работы с потоками

Допустим, что в файле хранятся сведения о мониторах. В каждой строке указан тип, оптовая и розничная цены и примечание. Для простоты данные в каждой строке записаны единообразно: первые 20 символов занимает тип монитора, далее по 5 символов целые числа, представляющие оптовую и розничную цены, затем примечание длиной не более 40 символов.

Приведенная ниже программа построчно считывает данные из текстового файла в буферную переменную s , затем формирует из них структуру m on и записывает ее в двоичном режиме в выходной файл. Далее производится считывание из этого файла произвольной записи.

FILE * fi , * fo ;

cout << "Ошибка открытия входного файла"; return 1;>

cout << "Ошибка открытия выходного файла"; return 1;>

const int dl = 80;

char type[20];

int opt, rozn;

char comm [40];

int kol = 0; // Количество записей в файле

while ( fgets ( s , dl , fi )) // Преобразование строки в структуру:

Т екстовые файлы хранят данные в виде текста (sic!). Это значит, что если, например, мы записываем целое число 12345678 в файл, то записывается 8 символов, а это 8 байт данных, несмотря на то, что число помещается в целый тип. Кроме того, вывод и ввод данных является форматированным, то есть каждый раз, когда мы считываем число из файла или записываем в файл происходит трансформация числа в строку или обратно. Это затратные операции, которых можно избежать.

Текстовые файлы позволяют хранить информацию в виде, понятном для человека. Можно, однако, хранить данные непосредственно в бинарном виде. Для этих целей используются бинарные файлы.

Выполните программу и посмотрите содержимое файла output.bin. Число, которое ввёл пользователь записывается в файл непосредственно в бинарном виде. Можете открыть файл в любом редакторе, поддерживающем представление в шестнадцатеричном виде (Total Commander, Far) и убедиться в этом.

Запись в файл осуществляется с помощью функции

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

Запись в бинарный файл объекта похожа на его отображение: берутся данные из оперативной памяти и пишутся как есть. Для считывания используется функция fread

Функция возвращает число удачно прочитанных элементов, которые помещаются по адресу ptr. Всего считывается count элементов по size байт. Давайте теперь считаем наше число обратно в переменную.

fseek

Одной из важных функций для работы с бинарными файлами является функция fseek

Эта функция устанавливает указатель позиции, ассоциированный с потоком, на новое положение. Индикатор позиции указывает, на каком месте в файле мы остановились. Когда мы открываем файл, позиция равна 0. Каждый раз, записывая байт данных, указатель позиции сдвигается на единицу вперёд.
fseek принимает в качестве аргументов указатель на поток и сдвиг в offset байт относительно origin. origin может принимать три значения

  • SEEK_SET - начало файла
  • SEEK_CUR - текущее положение файла
  • SEEK_END - конец файла. К сожалению, стандартом не определено, что такое конец файла, поэтому полагаться на эту функцию нельзя.

В случае удачной работы функция возвращает 0.

Дополним наш старый пример: запишем число, затем сдвинемся указатель на начало файла и прочитаем его.

Вместо этого можно также использовать функцию rewind, которая перемещает индикатор позиции в начало.

В си определён специальный тип fpos_t, который используется для хранения позиции индикатора позиции в файле.
Функция

используется для того, чтобы назначить переменной pos текущее положение. Функция

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

возвращает текущее положение индикатора относительно начала файла. Для бинарных файлов - это число байт, для текстовых не определено (если текстовый файл состоит из однобайтовых символов, то также число байт).

Рассмотрим пример: пользователь вводит числа. Первые 4 байта файла: целое, которое обозначает, сколько чисел было введено. После того, как пользователь прекращает вводить числа, мы перемещаемся в начало файла и записываем туда число введённых элементов.

Вторая программа сначала считывает количество записанных чисел, а потом считывает и выводит числа по порядку.

Примеры

1. Имеется бинарный файл размером 10*sizeof(int) байт. Пользователь вводит номер ячейки, после чего в неё записывает число. После каждой операции выводятся все числа. Сначала пытаемся открыть файл в режиме чтения и записи. Если это не удаётся, то пробуем создать файл, если удаётся создать файл, то повторяем попытку открыть файл для чтения и записи.

2. Пишем слова в бинарный файл. Формат такой - сначало число букв, потом само слово без нулевого символа. Ели длина слова равна нулю, то больше слов нет. Сначала запрашиваем слова у пользователя, потом считываем обратно.

3. Задача - считать данные из текстового файла и записать их в бинарный. Для решения зачи создадим функцию обёртку. Она будет принимать имя файла, режим доступа, функцию, которую необходимо выполнить, если файл был удачно открыт и аргументы этой функции. Так как аргументов может быть много и они могут быть разного типа, то их можно передавать в качестве указателя на структуру. После выполнения функции файл закрывается. Таким образом, нет необходимости думать об освобождении ресурсов.

4. Функция saveInt32Array позволяет сохранить массив типа int32_t в файл. Обратная ей loadInt32Array считывает массив обратно. Функция loadInt32Array сначала инициализирует переданный ей массив, поэтому мы должны передавать указатель на указатель; кроме того, она записывает считанный размер массива в переданный параметр size, из-за чего он передаётся как указатель.

5. Создание таблицы поиска. Для ускорения работы программы вместо вычисления функции можно произвести сначала вычисление значений функции на интервале с определённой точностью, после чего брать значения уже из таблицы. Программа сначала производит табулирование функции с заданными параметрами и сохраняет его в файл, затем подгружает предвычисленный массив, который уже используется для определения значений. В этой программе все функции возвращают переменную типа Result, которая хранит номер ошибки. Если функция отработала без проблем, то она возвращает Ok (0).

6. У нас имеются две структуры. Первая PersonKey хранит логин, пароль, id пользователя и поле offset. Вторая структура PersonInfo хранит имя и фамилию пользователя и его возраст. Первые структуры записываются в бинарный файл keys.bin, вторые структуры в бинарный файл values.bin. Поле offset определяет положение соответствующей информации о пользователе во втором файле. Таким образом, получив PersonKey из первого файла, по полю offset можно извлечь из второго файла связанную с данным ключом информацию.

Зачем так делать? Это выгодно в том случае, если структура PersonInfo имеет большой размер. Извлекать массив маленьких структур из файла не накладно, а когда нам понадобится большая структура, её можно извлечь по уже известному адресу в файле.

email

Всё ещё не понятно? – пиши вопросы на ящик

Читайте также: