Положение указателя файла - PullRequest
1 голос
/ 15 сентября 2009

Вот фрагмент кода

typedef struct
{
   double testA;
   double testB[500];   
   bool isProcessed;
} MYSTURCT;

У меня есть двоичный файл, который написан с несколькими структурами типа "myStruct".

Теперь в другой функции я пытаюсь прочитать файл и обновить в середине.

void test()
{
    FILE* fp = fopen (testFile, "r+")

    MYSTURCT* myPtr = malloc (sizeof (MYSTRUCT));

    while ( fread (myPtr,sizeof(MYSTRUCT),1,fp) )
    {
        if (!myPtr->isProcessed)
        {
            //update some thing int he struct

            myPtr->testA = 100.00;

            fseek (fp, -sizeof(MYSTRUCT), SEEK_CUR);

            fwrite (myPtr,sizeof(MYSTRUCT), 1,fp);

        }
    }
}

Как только я нахожу что-то необработанное, я обновляю структуру в памяти, затем пытаюсь записать структуру на диск. (сначала ищем позицию CURR - sizeof (struct)) а затем записать структуру на диск.

То, что происходит в моем приложении, происходит после выполнения fseek, мой

fp -> _ ptr портится и теряет позицию в моем потоке.

Что-то не так, что я здесь делаю?

Ответы [ 6 ]

4 голосов
/ 16 сентября 2009

-sizeof(STRUCT) потенциально опасно. sizeof(STRUCT) - это тип без знака, и если он имеет ширину, равную int, то тип, который он продвигает (тип выражения -sizeof(STRUCT)), также будет без знака и будет иметь значение около UINT_MAX - sizeof(STRUCT) + 1 или, возможно, ULONG_MAX - sizeof(STRUCT)+ 1 .

Если вам не повезло (например, 32-битный size_t, 64-битная длина), его UINT_MAX - sizeof(STRUCT) + 1 и long int могут удерживать это большое положительное значение, и поиск не будет выполнять то, что вы хотите.

Вы можете подумать о сохранении и восстановлении позиции:

fpos_t pos;

if (fgetpos(fp, &pos) != 0)
{
    /* position save failed */
    return;
}

/* read struct */

if (fsetpos(fp, &pos) != 0)
{
    /* position restore failed */
    return;
}

/* write struct */

fgetpos и fsetpos используют fpos_t, поэтому потенциально могут работать с очень большими файлами в сценариях, где fseek и ftell не будут.

2 голосов
/ 15 сентября 2009

На странице fopen написано:

Чтение и запись могут быть смешаны на чтение / запись потоков в любом порядке. Обратите внимание, что ANSI C требует, чтобы функция позиционирования файла вмешиваться между выводом и вводом, если только операция ввода не встречает конец чего-либо- файл. (Если это условие не выполняется, то чтение разрешено вернуть результат записи отличен от самого последнего.) Поэтому хорошо практика (и действительно иногда необходимая под Linux) положить Операция fseek (3) или fgetpos (3) между записью и чтением операции на такой поток. Эта операция может быть очевидной нет (как в fseek (..., 0L, SEEK_CUR) вызвал его побочный эффект синхронизации.

Так что вы можете попробовать вставить фиктивную подсказку сразу после написания.

1 голос
/ 16 сентября 2009

Вы используете malloc sizeof (MYSTRUCT) байт для myPtr, но myPtr имеет тип MYSTURCT.

Хотя я не думаю, что это твоя проблема.

Видимо, нет ничего плохого в вашем коде; попробуйте добавить проверку ошибок ...

void test(){
    FILE* fp = fopen (testFile, "r+"); /* missing semicolon */
    MYSTURCT* myPtr = malloc (sizeof *myPtr);
    while ( fread (myPtr,sizeof *myPtr,1,fp) == 1) /* error checking */
    {
        if (!myPtr->isProcessed)
        {
            //update some thing int he struct
            myPtr->testA = 100.00;
            if (fseek (fp, -sizeof *myPtr, SEEK_CUR) == -1)
            {
                perror("fseek");
            }
            if (fwrite (myPtr,sizeof *myPtr, 1,fp) != 1)
            {
                perror("fwrite");
            }
        }
    }
}

И fopen должен быть в двоичном режиме, даже если вы работаете в Linux (где это действительно не имеет значения). В Windows последовательность 0x0D 0x0A в середине одного из этих двойников будет преобразована в 0x0D и все испортит.

1 голос
/ 15 сентября 2009

Попробуйте fflush после последнего fwrite (). Затем попробуйте создать новый тестовый файл, используя вашу текущую структуру. Возможно, вы изменили свою структуру, и ваш текущий тестовый файл имеет более старый недопустимый порядок байтов.

0 голосов
/ 30 апреля 2012

если вы хотите записать в файл, вы должны использовать «w + b», а не «r +», иначе fwrite завершится ошибкой и вернет код ошибки (Думаю).

0 голосов
/ 16 сентября 2009

Я попробовал ваш пример кода, и мне кажется, что он работает нормально (хотя я делаю это в C - я заменил "char" для вашего "логического")

Для отладки, откуда вы знаете, что fp поврежден? Необычно смотреть на членов структуры FILE. Каждый раз, когда вы выполняете fseek (), fread () или fwrite (), что вы выводите, когда вызываете ftell ()?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...