文件指针位置

时间:2009-09-15 19:34:11

标签: c file-io

以下是代码片段

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 个答案:

答案 0 :(得分:4)

-sizeof(STRUCT)具有潜在的危险性。 sizeof(STRUCT)是无符号类型,如果它至少与int一样宽,则它的提升类型(-sizeof(STRUCT)表达式的类型)也将是无符号的,其值约为{{1}或者可能是UINT_MAX - sizeof(STRUCT) + 1

如果你运气不好(例如32位size_t,64位长),它的ULONG_MAX - sizeof(STRUCT)+ 1UINT_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_tfseek不支持的情况下处理非常大的文件。

答案 1 :(得分:2)

fopen联机帮助页说:

  

读取和写入可以混合在一起   以任何顺序读/写流。          请注意,ANSI C要求具有文件定位功能   干预          除非输入操作遇到,否则输出和输入之间   结束-          文件。 (如果不满足此条件,则允许读取   返回          写入的结果不是最近的。)因此它是   好          练习(实际上有时在Linux下是必要的)   放一个          fseek(3)或fgetpos(3)写入和读取之间的操作   操作          这样的流。这种操作可能是显而易见的   无操作(如          fseek(...,0L,SEEK_CUR)调用了它的同步副作用。

所以你可能会尝试在你写完之后把假的fseek放进去。

答案 2 :(得分:1)

在最后一次fwrite()之后尝试fflush。然后尝试使用当前结构制作新的测试文件。可能是您更改了结构,并且当前测试文件具有较旧的无效字节顺序。

答案 3 :(得分:1)

你的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并将所有内容搞砸。

答案 4 :(得分:0)

我尝试了你的示例代码,它似乎对我很好(虽然我在C中做 - 我用“char”代替你的“boolean”)

对于调试,你怎么知道fp被破坏了?查看FILE结构的成员是不常见的。每次执行fseek(),fread()或fwrite()时,调用ftell()时的输出是什么?

答案 5 :(得分:0)

如果你想写文件你应该使用“w + b”而不是“r +”否则fwrite会失败并返回错误代码。 (我想)。