#c #fgets #fread
#c #fgets #fread
Вопрос:
В чем разница между fread и fgets при чтении из файла? Я использую тот же оператор fwrite, однако, когда я использую fgets для чтения в txt-файле, он работает по назначению, но когда я использую fread(), это не так.
Я переключился с fgets / fputs на fread / fwrite при чтении из файла и в файл. Я использовал fopen(rb / wb) для чтения в двоичном формате, а не в стандартных символах. Я понимаю, что fread также получит /0 нулевых байтов, а не только отдельные строки.
//while (fgets(buff,1023,fpinput) != NULL) //read in from file
while (fread(buff, 1, 1023, fpinput) != 0) // read from file
Я ожидаю, что буду считывать данные из файла в буфер, помещать буфер в общую память, а затем другой процесс будет считывать данные из общей памяти и записывать в новый файл.
Когда я использую fgets(), он работает по назначению с файлами .txt, но при использовании fread он добавляет одну строку из 300 ~ символов в буфер с новой строкой. Ни за что на свете не могу понять, почему.
Комментарии:
1.
fgets
прекращает чтение при обнаружении перевода строки.fread
не проверяет их.2.
fgets
добавляет значение NUL.fread
нет.3. Вы рассматривали buf как строку с нулевым завершением, когда это было не так?
4. Действительно?? fread считывает указанное количество (необработанных двоичных) байтов, в то время как fgets считывает текстовую строку до символа конца строки. И добавляет null. Вы можете использовать fread для текстовых файлов, но fgets для двоичных файлов обычно не является хорошей идеей. Не пропускайте лекции по C 😉
5. Я пытаюсь преобразовать все это только с помощью fread() / fwrite() . Но когда я использую fgets, это приводит к: prnt.sc/neq45x Но когда я использую fread(), это приводит к: prnt.sc/neq4bz
Ответ №1:
fgets
остановится при появлении новой строки. fread
нет. So fgets
обычно полезен только для текстовых файлов, хотя fread
может использоваться как для текстовых, так и для двоичных файлов.
Из стандарта C11:
Функция fgets считывает максимум на один меньше, чем количество символов, указанное n, из потока, на который указывает stream, в массив, на который указывает s . Никакие дополнительные символы не считываются после символа новой строки (который сохраняется) или после окончания файла. Нулевой символ записывается сразу после последнего символа, считанного в массив.
Функция fread считывает в массив, на который указывает ptr, до элементов nmemb, размер которых определяется size , из потока, на который указывает stream . Для каждого объекта выполняются вызовы size для функции fgetc, и результаты сохраняются в порядке чтения в массиве беззнаковых символов, точно перекрывающих объект. Индикатор положения файла для потока (если он определен) увеличивается на количество успешно прочитанных символов. Если возникает ошибка, результирующее значение индикатора положения файла для потока не определено. Если считывается частичный элемент, его значение не определено.
Возможно, этот фрагмент прояснит для вас ситуацию. Он просто копирует файл по частям.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char ** argv)
{
if(argc != 3) {
printf("Usage: ./a.out src dstn");
printf("Copies file src to dstn");
exit(EXIT_SUCCESS);
}
const size_t chunk_size = 1024;
FILE *in, *out;
if(! (in = fopen(argv[1], "rb"))) exit(EXIT_FAILURE);
if(! (out = fopen(argv[2], "wb"))) exit(EXIT_FAILURE);
char * buffer;
if(! (buffer = malloc(chunk_size))) exit(EXIT_FAILURE);
size_t bytes_read;
do {
// fread returns the number of successfully read elements
bytes_read = fread(buffer, 1, chunk_size, in);
/* Insert any modifications you may */
/* want to do here */
// write bytes_read bytes from buffer to output file
if(fwrite(buffer, 1, bytes_read, out) != bytes_read) exit(EXIT_FAILURE);
// When we read less than chunk_size we are either done or an error has
// occured. This error is not handled in this program.
} while(bytes_read == chunk_size);
free(buffer);
fclose(out);
fclose(in);
}
Вы упомянули в комментарии ниже, что хотели использовать это для обмена байтами. Ну, вы можете просто использовать следующий фрагмент. Просто вставьте его туда, где указано в приведенном выше коде.
for(int i=0; i < bytes_read - bytes_read%2; i =2) {
char tmp = buffer[i];
buffer[i] = buffer[i 1];
buffer[i 1] = tmp;
}
Комментарии:
1. Должен ли я использовать тип size_t buff[1024] при работе с байтами, а не с буфером символов [1024]? Моя конечная цель с помощью этой программы — выполнить простой обмен байтами, где abcdef становится -> badcfe. Затем я хочу снова запустить программу, чтобы поменять ее обратно. Он должен иметь возможность работать с файлами .txt и .png. Вот почему я начинаю с более простого .txt, прежде чем переходить к .png. Я подумал, что, поскольку символы представляют собой один байт в памяти, это должно работать? @Broman
2. @RemiliaScarlet я не уверен, что вы здесь имеете в виду. Буфер имеет тип
char*
. Если ваша цель — двоичные файлы, вам следует начать с двоичных файлов. Процедура в основном та же, но инструменты сильно отличаются, и если она работает с двоичными файлами, она также будет работать с текстовыми файлами. В конце концов, текстовые файлы — это подмножество двоичных файлов.3. Ах, моя ошибка, и да, моя проблема в том, что я не знаком с новыми инструментами, необходимыми для выполнения этого с помощью двоичных файлов, а не строк. Я продолжу возиться с этим.
4. @RemiliaScarlet Не стесняйтесь использовать приведенный выше код. Похоже, вы могли бы использовать его как есть. Просто вставьте свой код модификации туда, где я указал его выше.
5. Я сейчас возлюсь с этим, это работает для копирования данных и их записи, я только что попробовал это с png, и он сделал это правильно, то же самое с .txt. Я заставлю это работать! Огромное спасибо за помощь, я возился с этим последние 10 ~ часов, ха-ха