Запазване на файловия указател между извикванията на функция

Имам код, при който имам достъп до двоичен файл няколко пъти. Всеки път, когато извикам функцията, тя отваря файла за четене и чете само необходимия брой байтове (да кажем 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 директно, освен ако не искате да добавите неща като грешка print към нея.

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