Чтение неизвестного количества структур из файла - C

У меня возникли проблемы с тем, чтобы моя программа считывала данные из файла. Проблема в том, что файл в настоящее время пуст. Каждый раз, когда программа запускается, один массив books[] будет заполняться и записываться в файл позже в коде. Хотя я уверен, что это будет работать, когда все 10 структур находятся в файле, на данный момент происходит сбой, так как файл пуст и он пытается прочитать 10 структур.

Есть ли способ прочитать неизвестное количество структур (до 10) из файла?

struct stock
{
    char name[31];
    int stock;
};

int main (void)
{
    stock books[10];

    FILE *fptr;
    fptr = fopen("stock.dat", "rb");
    fread(books, sizeof(struct stock), 10, fptr);

    fclose (fptr);
}

person karoma    schedule 23.03.2012    source источник
comment
где вылетает? в чем ошибка? это сводящее с ума почти полное описание проблемы.   -  person tbert    schedule 23.03.2012
comment
Если вы контролируете формат файла (т. е. он не определен кем-то другим), я рекомендую использовать текстовый формат (например, имя, по одному на строку) вместо двоичного. Это будет означать немного больше кода, но вы пишете код только один раз; файл будет намного удобнее.   -  person William Morris    schedule 23.03.2012


Ответы (6)


Если вы знаете максимально возможное количество структур в файле и можете позволить себе иметь их все в памяти:

int main (void)
{
    #define MAX_BOOKS 10
    stock books[MAX_BOOKS];
    size_t cnt_books = 0;
    FILE *fptr;
    fptr = fopen("stock.dat", "rb");
    cnt_books = fread(books, sizeof(struct stock), MAX_BOOKS, fptr);
    fclose (fptr);
    return 0;
}

в противном случае цикл и чтение кусками:

    while (cnt_books = fread(books, sizeof(struct stock), MAX_BOOKS, fptr)) {
      /* ... */
    }
person perreal    schedule 23.03.2012

Да, ты можешь сделать это:

  • Вам нужно проверить значение, возвращаемое fopen, чтобы убедиться, что файл существует.
  • Вам нужно проверить количество прочитанных элементов - значение size_t, возвращаемое fread
person cnicutar    schedule 23.03.2012

Сбой? Надеюсь, не те утверждения, если только файла там нет вообще. Это может привести к сбою, если вы предполагаете, что в вашем массиве есть десять допустимых элементов, поскольку поля name, вероятно, не будут допустимыми строками C.

Способ, которым вы определяете, сколько вы на самом деле читаете, заключается в следующем:

num = fread(books, sizeof(struct stock), 10, fptr);

хотя я бы предпочел:

num = fread (book, sizeof(*book), sizeof(book) / sizeof(*book), fptr);

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

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

#include <stdio.h>

typedef struct {
    char name[31];
    int stock;
} tStock;

int main (void) {
    tStock book[10];
    size_t num, i;

    FILE *fptr = fopen ("stock.dat", "rb");
    if (fptr == NULL) {
        num = 0;
    } else {
        num = fread (book, sizeof(*book), sizeof(book) / sizeof(*book), fptr);
        fclose (fptr);
    }

    printf ("Read %d items\n", num);
    for (i = 0; i < num; i++) {
        printf ("   Item %d is %s, %d\n", book[i].name, book[i].stock);
    }

    return 0;
}
person paxdiablo    schedule 23.03.2012

Код выглядит нормально (хотя еще не пробовал). См. fread справочную страницу — она возвращает количество прочитанных элементов.

person Ed Heal    schedule 23.03.2012

Я не уверен, но fread() не должен вызывать сбой, а должен возвращать количество прочитанных элементов, которое в данном случае равно 0. Также я не совсем понимаю, как компилируется строка stock books[10];, она должна быть struct stock books[10];.

Я бы предложил две вещи: 1. заменить на struct stock books[10]; 2. Важно проверить, что fptr не равен NULL. Возможно, он не смог открыть файл (возможно, не в том же каталоге или еще не существует), что приводит к NULL fptr, и использование его в fread приведет к сбою приложения.

person Israel Unterman    schedule 23.03.2012
comment
stock books[10]; будет компилироваться компилятором C++ - person gbulmer; 23.03.2012

person    schedule
comment
@CodeChordsman Действительно, мой код был совершенно неправильным, я тоже это заметил. Спасибо за исправление. - person Lundin; 23.03.2012