Выход из файла с помощью функции feof

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

if (feof(file))
{
   return 2;
}

После функции fread:

fread(array, 1, 512, file);

Таким образом, если fread читает до конца файла, запускается feof и, таким образом, завершается программа. Это мой код:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        printf("Invalid entry.\n");
        return 0;
    }

    int counter = 1;
    FILE* images;
    char jpg_name[8];

    // Check if bytes are jpg. signatures.
    for (int n = 0; counter < 51; n = n + 512)
    {
        // Open file for reading.
        FILE *file = fopen(argv[1], "r");
        if (!file)
        {
            return 1;
        }

        unsigned char array[512];
        fseek(file, n, SEEK_SET);
        fread(array, 1, 512, file); // if EOF, won't have 512 to write into!!!
        if (feof(file))
        {
            return 2;
        }
        fclose(file);

        if (array[0] == 0xff && array[1] == 0xd8 && array[2] == 0xff && (array[3] & 0xf0) == 0xe0)
        {
            // Convert integer to string and store into jpg character array. Increment image number.
            sprintf(jpg_name, "%03i.jpg", counter);
            counter++;

            // Open images file to write into, allocate memory to jpg file to write into, write 512 bytes from array into image file.
            images = fopen(jpg_name, "a");
            fwrite(array, 1, 512, images);
            fclose(images);
        }
        else // If 1st 4 bytes aren't jpg signature.
        {
            if (counter > 1)
            {
                images = fopen(jpg_name, "a");
                fwrite(array, 1, 512, images);
                fclose(images);
            }
        }
    }
}

Я также попытался поставить условие:

if (fread(array, 1, 512, file) == 512)

В программу, чтобы она перестала работать после того, как прочитает менее 512 байт, чтобы остановить автоматическую остановку программы, но это тоже, похоже, не работает.

Будем очень признательны за любые разъяснения или советы, спасибо!


person ckwan    schedule 14.07.2020    source источник
comment
Пожалуйста, опишите поведение лучше, чем не работает. Каким должен быть входной файл argv[1] и как он соотносится с другими обрабатываемыми jpg_name файлами?   -  person kaylum    schedule 14.07.2020
comment
Это не цель feof. После того, как операция чтения указывает, что данные были использованы, вы используете feof, чтобы определить, обнаружила ли операция чтения ошибку или прочитала все данные.   -  person William Pursell    schedule 14.07.2020
comment
@kaylum Извините за неясность. argv [1] - это имя файла, из которого я хочу извлечь изображения. jpg_name относится к имени каждого изображения, которое я извлекаю; Я пытаюсь пронумеровать jpg. численно, начиная с 1. Поскольку нужно извлечь 50 фотографий, я хотел бы остановить программу после того, как все 50 изображений будут извлечены. К сожалению, моя программа не знает, когда завершить работу, и поэтому я считаю, что последняя фотография перезаписывается несколько раз, и я не знаю, как это исправить.   -  person ckwan    schedule 14.07.2020
comment
@WilliamPursell Итак, в настоящее время моя функция 'fread' читает по 512 байтов за раз, как только она дойдет до конца файла, будет ли она читать последние 512 байтов файла (поэтому перечитывает некоторые из предыдущих байтов для последней фотографии более одного раза), или он читает x доступных байтов, а остальная часть массива остается пустой, потому что больше нет байтов для чтения?   -  person ckwan    schedule 14.07.2020
comment
Он будет читать только то количество, которое доступно, и fread вернет общее количество прочитанных. Массив после этого останется без изменений.   -  person William Pursell    schedule 14.07.2020
comment
относительно: fread(array, 1, 512, file); // if EOF, won't have 512 to write into!!! if (feof(file)) Вызов feof() только в том случае, если возвращаемое значение из fread() == 0; в противном случае, если только что был прочитан последний входной файл, тогда feof() вернет «истину», НО последние считанные данные не будут обработаны.   -  person user3629249    schedule 15.07.2020


Ответы (1)


Не открывайте и не закрывайте файл каждый раз в цикле. Просто прочтите файл блоками по 512, пока он не достигнет EOF.

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define SIZE 512

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        printf("Invalid entry.\n");
        return 0;
    }

    int counter = 1;
    FILE* images;
    char jpg_name[8];

    // Open file for reading.
    FILE *file = fopen(argv[1], "r");
    if (!file)
    {
        return 1;
    }

    unsigned char array[SIZE];

    // Check if bytes are jpg. signatures.
    while (fread(array, 1, SIZE, file) == 1)
    {
        if (array[0] == 0xff && array[1] == 0xd8 && array[2] == 0xff && (array[3] & 0xf0) == 0xe0)
        {
            // Convert integer to string and store into jpg character array. Increment image number.
            sprintf(jpg_name, "%03i.jpg", counter);
            counter++;

            // Open images file to write into, allocate memory to jpg file to write into, write 512 bytes from array into image file.
            images = fopen(jpg_name, "a");
            fwrite(array, 1, 512, images);
            fclose(images);
        }
        else // If 1st 4 bytes aren't jpg signature.
        {
            if (counter > 1)
            {
                images = fopen(jpg_name, "a");
                fwrite(array, 1, 512, images);
                fclose(images);
            }
        }
    }
    fclose(file);
}
person Barmar    schedule 14.07.2020
comment
относительно: while (fread(array, 1, SIZE, file) == 1) это неправильное сравнение. Это третье значение параметра, которое будет возвращено при успешном вызове. I.E. while ( fread( array, 1, SIZE, file ) == SIZE ) - person user3629249; 15.07.2020
comment
Плохая идея - открывать / закрывать файл снова и снова. Настоятельно рекомендуем использовать только байты «4 jpg header» как причину (возможно) закрыть предыдущий выходной файл, а затем открыть новый файл. - person user3629249; 15.07.2020
comment
@ user3629249 Изначально я убрал это из цикла, но потом заметил, что имя файла зависит от counter. Я не хотел усложнять ответ всей логикой, необходимой для определения, когда открывать и закрывать файл. На самом деле накладных расходов не так много, чтобы это исправить. - person Barmar; 15.07.2020
comment
На самом деле открытие / закрытие файла - это наиболее вероятная ошибка ввода-вывода. Таким образом, код должен минимизировать количество этих событий. - person user3629249; 15.07.2020
comment
@ user3629249 Или, может быть, наоборот, чтобы вы могли обнаружить ошибку как можно раньше. - person Barmar; 15.07.2020
comment
Если вы не выполните операцию ввода-вывода, то ошибки ввода-вывода возникнуть не может. - person user3629249; 15.07.2020
comment
@ user3629249 Если диск вышел из строя, вы хотели бы выяснить это как можно скорее, а не ждать намного позже, когда вы попытаетесь записать все буферизованные данные. - person Barmar; 15.07.2020
comment
диск (и структуры данных в памяти) намного надежнее, если его не нужно модифицировать для каждой записи данных с дополнительными операциями открытия и закрытия. Меньше операций == больше надежности - person user3629249; 15.07.2020
comment
@ user3629249 Вы действительно недооцениваете надежность. Если вы не говорите о порядках величин, на самом деле это никого не беспокоит. - person Barmar; 15.07.2020