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

У меня есть код, в котором я несколько раз обращаюсь к двоичному файлу. Каждый раз, когда я вызываю функцию, она открывает файл для чтения и считывает только необходимое количество байтов (скажем, n байт каждый раз).

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

Функция выглядит так:

int readBinary(float *binImage, int gelements) {
    imageFile = fopen("tmpImageFile", "r");
    if (imageFile == NULL) {
       fprintf(stderr, "Error opening file\n");
       return (1);
    }
    fread(binImage, sizeof(float), gelements, imageFile);
    return 0;
}

И в моем основном коде я хотел бы запустить его через цикл, каждый раз давая ему массив binImage размера gelements. Я бы предпочел не давать ему массив размером gelements * nLoop, если этого можно избежать.


person Kitchi    schedule 20.04.2013    source источник
comment
Почему вы продолжаете открывать файл? Просто откройте его один раз и продолжайте использовать его.   -  person Barmar    schedule 20.04.2013


Ответы (4)


Быстрые эмпирические правила

"Жизнь станет проще, если вы правильно распределите обязанности между функциями"

и

«Жизнь усложняется, если вы используете статические или глобальные переменные».

В этом случае возлагать на функцию readBinary одновременно ответственность за управление FILE и чтение данных — это слишком.

Обратите внимание, что функция не закрывает дескриптор.

Если дескриптор является локальным статическим элементом в функции, то закрыть его будет невозможно. Это также означает, что функция будет навсегда заблокирована для использования только «tmpImageFile» (что не сразу видно из подписи функции или отсутствующей документации).

Если дескриптор является глобальным, его можно закрыть преждевременно.

Обратите внимание, что если вы удалите ответственность за «открытие файла», функция readBinary будет просто вызовом fread.

Лучший способ справиться с этим — вообще пропустить функцию readBinary.

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

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

person Andrei    schedule 20.04.2013

Используйте статическую переменную, чтобы сохранить указатель файла:

int readBinary(float *binImage, int gelements) {
    static FILE *imageFile = NULL;
    if (imageFile == NULL) {
       imageFile = fopen("tmpImageFile", "r");
       if (imageFile == NULL) {
          perror("Error opening file: ");
          return (1);
       }
    }
    fread(binImage, sizeof(float), gelements, imageFile);
    return 0;
}
person Barmar    schedule 20.04.2013

Я бы передал параметр FILE* как функцию:

int readBinary(float *binImage, int gelements, FILE *imageFile) {
    int bytes = fread(binImage, sizeof(float), gelements, imageFile);
    return bytes != -1 ? 0 : 1;
}

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

person hyde    schedule 20.04.2013

Вы можете сделать указатель файла статическим и инициализировать его значением NULL. Затем в следующий раз, если он не равен NULL, он содержит открытый файл. Также при закрытии файла убедитесь, что вы снова сделали его равным NULL. То же самое можно сделать и с глобальным указателем

int readBinary(float *binImage, int gelements) {
static imageFile = NULL;
if(imageFile == NULL ) imageFile = fopen("tmpImageFile", "r");
if (imageFile == NULL) {
   fprintf(stderr, "Error opening file\n");
   return (1);
}
fread(binImage, sizeof(float), gelements, imageFile);
return 0;
}
person abasu    schedule 20.04.2013