以下是代码片段
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搞砸了,它在我的信息流中失去了位置跟踪。
我在这里做错了吗?
答案 0 :(得分:4)
-sizeof(STRUCT)
具有潜在的危险性。 sizeof(STRUCT)
是无符号类型,如果它至少与int一样宽,则它的提升类型(-sizeof(STRUCT)
表达式的类型)也将是无符号的,其值约为{{1}或者可能是UINT_MAX - sizeof(STRUCT) + 1
。
如果你运气不好(例如32位size_t,64位长),它的ULONG_MAX - sizeof(STRUCT)+ 1
和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
不支持的情况下处理非常大的文件。
答案 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会失败并返回错误代码。 (我想)。