I write this C code so that I could test whether fwrite could update some values in a text file. I tested on Linux and it works fine. In Windows (vista 32bits), however, it simply does not work. The file remains unchanged after I write a different byte using: cont = fwrite(&newfield, sizeof(char), 1, fp);
我编写这个C代码,以便我可以测试fwrite是否可以更新文本文件中的某些值。我在Linux上测试过它运行正常。但是,在Windows(vista 32bits)中,它根本不起作用。使用以下命令写入不同的字节后,文件保持不变:cont = fwrite(&newfield,sizeof(char),1,fp);
The registers are written on the file using a "@" separator, in the format:
寄存器使用“@”分隔符写入文件,格式如下:
Reg1FirstField@Reg1SecondField@Reg2FirstField@Reg2SecondField...
The final file should be: First@1@Second@9@Third@1@
最终文件应该是:First @ 1 @ Second @ 9 @ Third @ 1 @
I also tried putc and fprintf, all with no result. Can someone please help me with this?
我也试过putc和fprintf,都没有结果。有人可以帮我这个吗?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct test {
char field1[20];
char field2;
} TEST;
int main(void) {
FILE *fp;
TEST reg, regread;
char regwrite[22];
int i, cont, charwritten;
fp=fopen("testupdate.txt","w+");
strcpy(reg.field1,"First");
reg.field2 = '1';
sprintf(regwrite,"%s@%c@", reg.field1, reg.field2);
cont = (int)strlen(regwrite);
charwritten = fwrite(regwrite,cont,1,fp);
fflush(fp);
strcpy(reg.field1,"Second");
reg.field2 = '1';
sprintf(regwrite,"%s@%c@", reg.field1, reg.field2);
cont = (int)strlen(regwrite);
charwritten = fwrite(regwrite,cont,1,fp);
fflush(fp);
strcpy(reg.field1,"Third");
reg.field2 = '1';
sprintf(regwrite,"%s@%c@", reg.field1, reg.field2);
cont = (int)strlen(regwrite);
charwritten = fwrite(regwrite,cont,1,fp);
fflush(fp);
fclose(fp);
// open file to update
fp=fopen("testupdate.txt","r+");
printf("\nUpdate field 2 on the second register:\n");
char aux[22];
// search for second register and update field 2
for (i = 0; i < 3; i ++) {
fscanf(fp,"%22[^@]@", aux);
printf("%d-1: %s\n", i, aux);
if (strcmp(aux, "Second") == 0) {
char newfield = '9';
cont = fwrite(&newfield, sizeof(char), 1, fp);
printf("written: %d bytes, char: %c\n", cont, newfield);
// goes back one byte in order to read properly
// on the next fscanf
fseek(fp,-1,SEEK_CUR);
}
fscanf(fp,"%22[^@]@", aux);
printf("%d-2: %s\n",i, aux);
aux[0] = '\0';
}
fflush(fp);
fclose(fp);
// open file to see if the update was made
fp=fopen("testupdate.txt","r");
for (i = 0; i < 3; i ++) {
fscanf(fp,"%22[^@]@", aux);
printf("%d-1: %s\n", i, aux);
fscanf(fp,"%22[^@]@",aux);
printf("%d-2: %s\n",i, aux);
aux[0] = '\0';
}
fclose(fp);
getchar();
return 0;
}
5 个解决方案
#1
3
You're missing a file positioning function between the read and write. The Standard says:
您在读取和写入之间缺少文件定位功能。标准说:
7.19.5.3/6
When a file is opened with update mode, both input and output may be performed on the associated stream. However, ... input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file. ...
使用更新模式打开文件时,可以在关联的流上执行输入和输出。但是,除非输入操作遇到文件结束,否则输入不应直接跟随输出而不插入文件定位功能。 ...
for (i = 0; i < 3; i ++) {
fscanf(fp,"%22[^@]@", aux); /* read */
printf("%d-1: %s\n", i, aux);
if (strcmp(aux, "Second") == 0) {
char newfield = '9';
/* added a file positioning function */
fseek(fp, 0, SEEK_CUR); /* don't move */
cont = fwrite(&newfield, sizeof(char), 1, fp); /* write */
#2
3
I didn't know it but here they explain it: why fseek or fflush is always required between reading and writing in the read/write "+" modes
我不知道但在这里他们解释了:为什么在读/写“+”模式下读写之间总是需要fseek或fflush
Conclusion: You must either fflush
or fseek
before every write when you use "+"
.
结论:当您使用“+”时,您必须在每次写入之前使用fflush或fseek。
fseek(fp, 0, SEEK_CUR);
// or
fflush(fp);
cont = fwrite(&newfield, sizeof(char), 1, fp);
Fix verified on Cygwin.
修复了在Cygwin上的验证。
#3
0
You're not checking any return values for errors. I'm guessing the file is read-only and is not even opening properly.
您没有检查错误的任何返回值。我猜这个文件是只读的,甚至没有正确打开。
#4
0
At least here on OSX, your value 9
is begin appended to the end of the file ... so you're not updating the actual register value for Second
at it's position in the file. For some reason after the scan for the appropriate point to modify the values, your stream pointer is actually at the end of the file. For instance, running and compiling your code on OSX produced the following output in the actual text file:
至少在OSX上,你的值9开始附加到文件的末尾...所以你不是在文件的位置更新Second的实际寄存器值。出于某种原因,在扫描适当的点以修改值之后,您的流指针实际上位于文件的末尾。例如,在OSX上运行和编译代码会在实际文本文件中生成以下输出:
First@1@Second@1@Third@1@9
The reason your initial read-back is working is because the data is being written, but it's at the end of the file. So when you write the value and then back-up the stream and re-read the value, that works, but it's not being written in the location you're assuming.
您的初始回读工作原因是因为正在写入数据,但它位于文件的末尾。因此,当您编写该值然后备份流并重新读取该值时,该工作正常,但它并未写入您所假设的位置。
Update: I've added some calls to ftell
to see what's happening to the stream pointer, and it seems that your calls to fscanf
are working as you'd assume, but the call to fwrite
is jumping to the end of the file. Here's the modified output:
更新:我添加了一些调用ftell以查看流指针发生了什么,似乎你对fscanf的调用正如你所假设的那样,但是对fwrite的调用正在跳转到文件的末尾。这是修改后的输出:
Update field 2 on the second register:
**Stream position: 0
0-1: First
0-2: 1
**Stream position: 8
1-1: Second
**Stream position before write: 15
**Stream position after write: 26
written: 1 bytes, char: 9
1-2: 9
**Stream position after read-back: 26
Update-2: It seems by simply saving the position of the stream-pointer, and then setting the position of the stream-pointer, the call to 'fwrite` worked without skipping to the end of the file. So I added:
Update-2:似乎只需保存流指针的位置,然后设置流指针的位置,对'fwrite`的调用就可以在不跳到文件末尾的情况下工作。所以我补充说:
fpos_t position;
fgetpos(fp, &position);
fsetpos(fp, &position);
right before the call to fwrite
. Again, this is on OSX, you may see something different on Windows.
就在调用fwrite之前。再次,这是在OSX上,您可能会在Windows上看到不同的东西。
#5
-2
With this:
fp=fopen("testupdate.txt","w+");
^------ Notice the + sign
You opened the file in "append" mode -- that is what the plus sign does in this parameter. As a result, all of your fwrite()
calls will be relative to the end of the file.
您以“追加”模式打开文件 - 这是加号在此参数中的作用。因此,所有fwrite()调用都将相对于文件末尾。
Using "r+"
for the fopen()
mode doesn't make sense -- the +
means nothing in this case.
对fopen()模式使用“r +”没有意义 - 在这种情况下,+表示没有任何意义。
This and other issues with fopen()
are why I prefer to use the POSIX-defined open()
.
fopen()的这个问题和其他问题是我更喜欢使用POSIX定义的open()的原因。
To fix your particular case, get rid of the +
characters from the fopen()
modes, and consider that you might need to specify binary format on Windows ("wb"
and "rb"
modes).
要修复您的特定情况,请从fopen()模式中删除+字符,并考虑您可能需要在Windows上指定二进制格式(“wb”和“rb”模式)。
#1
3
You're missing a file positioning function between the read and write. The Standard says:
您在读取和写入之间缺少文件定位功能。标准说:
7.19.5.3/6
When a file is opened with update mode, both input and output may be performed on the associated stream. However, ... input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file. ...
使用更新模式打开文件时,可以在关联的流上执行输入和输出。但是,除非输入操作遇到文件结束,否则输入不应直接跟随输出而不插入文件定位功能。 ...
for (i = 0; i < 3; i ++) {
fscanf(fp,"%22[^@]@", aux); /* read */
printf("%d-1: %s\n", i, aux);
if (strcmp(aux, "Second") == 0) {
char newfield = '9';
/* added a file positioning function */
fseek(fp, 0, SEEK_CUR); /* don't move */
cont = fwrite(&newfield, sizeof(char), 1, fp); /* write */
#2
3
I didn't know it but here they explain it: why fseek or fflush is always required between reading and writing in the read/write "+" modes
我不知道但在这里他们解释了:为什么在读/写“+”模式下读写之间总是需要fseek或fflush
Conclusion: You must either fflush
or fseek
before every write when you use "+"
.
结论:当您使用“+”时,您必须在每次写入之前使用fflush或fseek。
fseek(fp, 0, SEEK_CUR);
// or
fflush(fp);
cont = fwrite(&newfield, sizeof(char), 1, fp);
Fix verified on Cygwin.
修复了在Cygwin上的验证。
#3
0
You're not checking any return values for errors. I'm guessing the file is read-only and is not even opening properly.
您没有检查错误的任何返回值。我猜这个文件是只读的,甚至没有正确打开。
#4
0
At least here on OSX, your value 9
is begin appended to the end of the file ... so you're not updating the actual register value for Second
at it's position in the file. For some reason after the scan for the appropriate point to modify the values, your stream pointer is actually at the end of the file. For instance, running and compiling your code on OSX produced the following output in the actual text file:
至少在OSX上,你的值9开始附加到文件的末尾...所以你不是在文件的位置更新Second的实际寄存器值。出于某种原因,在扫描适当的点以修改值之后,您的流指针实际上位于文件的末尾。例如,在OSX上运行和编译代码会在实际文本文件中生成以下输出:
First@1@Second@1@Third@1@9
The reason your initial read-back is working is because the data is being written, but it's at the end of the file. So when you write the value and then back-up the stream and re-read the value, that works, but it's not being written in the location you're assuming.
您的初始回读工作原因是因为正在写入数据,但它位于文件的末尾。因此,当您编写该值然后备份流并重新读取该值时,该工作正常,但它并未写入您所假设的位置。
Update: I've added some calls to ftell
to see what's happening to the stream pointer, and it seems that your calls to fscanf
are working as you'd assume, but the call to fwrite
is jumping to the end of the file. Here's the modified output:
更新:我添加了一些调用ftell以查看流指针发生了什么,似乎你对fscanf的调用正如你所假设的那样,但是对fwrite的调用正在跳转到文件的末尾。这是修改后的输出:
Update field 2 on the second register:
**Stream position: 0
0-1: First
0-2: 1
**Stream position: 8
1-1: Second
**Stream position before write: 15
**Stream position after write: 26
written: 1 bytes, char: 9
1-2: 9
**Stream position after read-back: 26
Update-2: It seems by simply saving the position of the stream-pointer, and then setting the position of the stream-pointer, the call to 'fwrite` worked without skipping to the end of the file. So I added:
Update-2:似乎只需保存流指针的位置,然后设置流指针的位置,对'fwrite`的调用就可以在不跳到文件末尾的情况下工作。所以我补充说:
fpos_t position;
fgetpos(fp, &position);
fsetpos(fp, &position);
right before the call to fwrite
. Again, this is on OSX, you may see something different on Windows.
就在调用fwrite之前。再次,这是在OSX上,您可能会在Windows上看到不同的东西。
#5
-2
With this:
fp=fopen("testupdate.txt","w+");
^------ Notice the + sign
You opened the file in "append" mode -- that is what the plus sign does in this parameter. As a result, all of your fwrite()
calls will be relative to the end of the file.
您以“追加”模式打开文件 - 这是加号在此参数中的作用。因此,所有fwrite()调用都将相对于文件末尾。
Using "r+"
for the fopen()
mode doesn't make sense -- the +
means nothing in this case.
对fopen()模式使用“r +”没有意义 - 在这种情况下,+表示没有任何意义。
This and other issues with fopen()
are why I prefer to use the POSIX-defined open()
.
fopen()的这个问题和其他问题是我更喜欢使用POSIX定义的open()的原因。
To fix your particular case, get rid of the +
characters from the fopen()
modes, and consider that you might need to specify binary format on Windows ("wb"
and "rb"
modes).
要修复您的特定情况,请从fopen()模式中删除+字符,并考虑您可能需要在Windows上指定二进制格式(“wb”和“rb”模式)。