在C中同时读取和写入文件
Reading and writing to a file at the same time in C
应该在文件中每两行交换一次,直到只剩下一行或所有行都用完。我不想在这样做时使用其他文件。
这是我的代码:
#include <stdio.h>
int main() {
FILE *fp = fopen("this.txt", "r+");
int i = 0;
char line1[100], line2[100];
fpos_t pos;
fgetpos(fp, &pos);
//to get the total line count
while (!feof(fp)) {
fgets(line1, 100, fp);
i++;
}
i /= 2; //no. of times to run the loop
rewind(fp);
while (i-- > 0) { //trying to use !feof(fp) condition to break the loop results in an infinite loop
fgets(line1, 100, fp);
fgets(line2, 100, fp);
fsetpos(fp, &pos);
fputs(line2, fp);
fputs(line1, fp);
fgetpos(fp, &pos);
}
fclose(fp);
return 0;
}
this.txt中的内容:
aaa
b
cc
ddd
ee
ffff
gg
hhhh
i
jj
运行程序后的内容
b
aaa
ddd
cc
ddd
c
c
c
i
jj
我什至尝试使用 fseek
代替 fgetpos
只是为了得到同样的错误结果。
根据我的计算,在第二个 while 循环 运行 两次 (即前四行已被处理) 之后,光标正确地位于第 17应该是 的字节(由对 ftell(fp)
的调用返回) 甚至第 4 行之后的文件内容都没有改变,并且由于某种原因 [=16] =]在第3次循环运行ning时被调用,读入数组line1和line2的内容分别为"c\n"和"ddd\n"。
再说一次,我不想使用其他文件来完成此操作,我只需要弄清楚屏幕背后到底出了什么问题
如有任何线索,我们将不胜感激。谢谢你。
更改文件的当前位置时不一定会刷新缓冲区。所以它必须显式刷新。
例如使用fflush(fp);
改变
fputs(line2,fp);
fputs(line1,fp);
至
fputs(line2,fp);
fputs(line1,fp);
fflush(fp);
您的代码中存在多个问题:
您不检查 fopen()
是否成功,冒着未定义行为的风险。
确定总行数的循环不正确。
在此处了解原因:Why is “while ( !feof (file) )” always wrong?
您实际上不需要计算总行数。
您应该调用fflush()
将内容写回文件,然后再从写回读更改。
C 标准对以更新模式打开的文件指定了此限制:
7.21.5.3 The fopen
function
[...] output shall not be directly followed by input without an intervening call to the fflush
function or to a file positioning function (fseek
, fsetpos
, or rewind
), and 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.
这解释了为什么仅在以相反顺序写入行后读取文件位置会导致问题。调用 fflush()
应该可以解决这个问题。
这是更正后的版本:
#include <stdio.h>
int main(void) {
FILE *fp;
char line1[100], line2[100];
fpos_t pos;
fp = fopen("this.txt", "r+");
if (fp == NULL) {
fprintf(stderr, "cannot open this.txt\n");
return 1;
}
while (fgetpos(fp, &pos) == 0 &&
fgets(line1, sizeof line1, fp) != NULL &&
fgets(line2, sizeof line2, fp) != NULL) {
fsetpos(fp, &pos);
fputs(line2, fp);
fputs(line1, fp);
fflush(fp);
}
fclose(fp);
return 0;
}
为什么不使用两个文件指针,都指向同一个文件,一个用于读取,一个用于写入?无需跟踪文件位置,无需四处寻找,也无需刷新。
这种方法可以省去很多复杂的事情。那些不必要的努力最好投入到一些复杂的错误中 checking/logging 如下 ;-):
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
int result = EXIT_SUCCESS;
size_t blocks = 0;
int l1_done = 0;
int l2_done = 0;
FILE *fpin = fopen("this.txt", "r");
FILE *fpout = fopen("this.txt", "r+");
if (NULL == fpin)
{
result = EXIT_FAILURE;
perror("fopen() to for reading failed");
}
if (NULL == fpout)
{
result = EXIT_FAILURE;
perror("fopen() for writing failed");
}
while (EXIT_SUCCESS == result && !l1_done && !l2_done)
{
result = EXIT_FAILURE;
char line1[100];
char line2[100];
if ((l1_done = (NULL == fgets(line1, sizeof line1, fpin))))
{
if (ferror(fpin))
{
fprintf(stderr, "Reading line %zu failed.\n", 2*blocks);
break;
}
}
if ((l2_done = (NULL == fgets(line2, sizeof line2, fpin))))
{
if (ferror(fpin))
{
fprintf(stderr, "Reading line %zu failed.\n", 2*blocks + 1);
break;
}
}
{
size_t len = strlen(line1);
if (((sizeof line1 - 1) == len) && ('\n' != line1[len]))
{
fprintf(stderr, "Line %zu too long or new-line missing.\n", 2*blocks);
break;
}
}
{
size_t len = strlen(line2);
if (((sizeof line2 - 1) == len) && ('\n' != line2[len]))
{
fprintf(stderr, "Line %zu too long or new-line missing.\n", 2*blocks + 1);
break;
}
}
if (!l2_done)
{
if (EOF == fputs(line2, fpout))
{
fprintf(stderr, "Writing line %zu as line %zu failed.\n", 2*blocks + 1, 2*blocks);
break;
}
}
if (!l1_done)
{
if (EOF == fputs(line1, fpout))
{
fprintf(stderr, "Writing line %zu as line %zu failed.\n", 2*blocks, 2*blocks + 1);
break;
}
}
++blocks;
result = EXIT_SUCCESS;
}
if (EXIT_SUCCESS == result && !ll_done && l2_done)
{
fprintf(stderr, "Odd number of lines.\n");
}
fclose(fpin); /* Perhaps add error checking here as well ... */
fclose(fpout); /* Perhaps add error checking here as well ... */
return result;
}
应该在文件中每两行交换一次,直到只剩下一行或所有行都用完。我不想在这样做时使用其他文件。
这是我的代码:
#include <stdio.h>
int main() {
FILE *fp = fopen("this.txt", "r+");
int i = 0;
char line1[100], line2[100];
fpos_t pos;
fgetpos(fp, &pos);
//to get the total line count
while (!feof(fp)) {
fgets(line1, 100, fp);
i++;
}
i /= 2; //no. of times to run the loop
rewind(fp);
while (i-- > 0) { //trying to use !feof(fp) condition to break the loop results in an infinite loop
fgets(line1, 100, fp);
fgets(line2, 100, fp);
fsetpos(fp, &pos);
fputs(line2, fp);
fputs(line1, fp);
fgetpos(fp, &pos);
}
fclose(fp);
return 0;
}
this.txt中的内容:
aaa
b
cc
ddd
ee
ffff
gg
hhhh
i
jj
运行程序后的内容
b
aaa
ddd
cc
ddd
c
c
c
i
jj
我什至尝试使用 fseek
代替 fgetpos
只是为了得到同样的错误结果。
根据我的计算,在第二个 while 循环 运行 两次 (即前四行已被处理) 之后,光标正确地位于第 17应该是 的字节(由对 ftell(fp)
的调用返回) 甚至第 4 行之后的文件内容都没有改变,并且由于某种原因 [=16] =]在第3次循环运行ning时被调用,读入数组line1和line2的内容分别为"c\n"和"ddd\n"。
再说一次,我不想使用其他文件来完成此操作,我只需要弄清楚屏幕背后到底出了什么问题
如有任何线索,我们将不胜感激。谢谢你。
更改文件的当前位置时不一定会刷新缓冲区。所以它必须显式刷新。
例如使用fflush(fp);
改变
fputs(line2,fp);
fputs(line1,fp);
至
fputs(line2,fp);
fputs(line1,fp);
fflush(fp);
您的代码中存在多个问题:
您不检查
fopen()
是否成功,冒着未定义行为的风险。确定总行数的循环不正确。
在此处了解原因:Why is “while ( !feof (file) )” always wrong?您实际上不需要计算总行数。
您应该调用
fflush()
将内容写回文件,然后再从写回读更改。
C 标准对以更新模式打开的文件指定了此限制:
7.21.5.3 The
fopen
function[...] output shall not be directly followed by input without an intervening call to the
fflush
function or to a file positioning function (fseek
,fsetpos
, orrewind
), and 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.
这解释了为什么仅在以相反顺序写入行后读取文件位置会导致问题。调用 fflush()
应该可以解决这个问题。
这是更正后的版本:
#include <stdio.h>
int main(void) {
FILE *fp;
char line1[100], line2[100];
fpos_t pos;
fp = fopen("this.txt", "r+");
if (fp == NULL) {
fprintf(stderr, "cannot open this.txt\n");
return 1;
}
while (fgetpos(fp, &pos) == 0 &&
fgets(line1, sizeof line1, fp) != NULL &&
fgets(line2, sizeof line2, fp) != NULL) {
fsetpos(fp, &pos);
fputs(line2, fp);
fputs(line1, fp);
fflush(fp);
}
fclose(fp);
return 0;
}
为什么不使用两个文件指针,都指向同一个文件,一个用于读取,一个用于写入?无需跟踪文件位置,无需四处寻找,也无需刷新。
这种方法可以省去很多复杂的事情。那些不必要的努力最好投入到一些复杂的错误中 checking/logging 如下 ;-):
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
int result = EXIT_SUCCESS;
size_t blocks = 0;
int l1_done = 0;
int l2_done = 0;
FILE *fpin = fopen("this.txt", "r");
FILE *fpout = fopen("this.txt", "r+");
if (NULL == fpin)
{
result = EXIT_FAILURE;
perror("fopen() to for reading failed");
}
if (NULL == fpout)
{
result = EXIT_FAILURE;
perror("fopen() for writing failed");
}
while (EXIT_SUCCESS == result && !l1_done && !l2_done)
{
result = EXIT_FAILURE;
char line1[100];
char line2[100];
if ((l1_done = (NULL == fgets(line1, sizeof line1, fpin))))
{
if (ferror(fpin))
{
fprintf(stderr, "Reading line %zu failed.\n", 2*blocks);
break;
}
}
if ((l2_done = (NULL == fgets(line2, sizeof line2, fpin))))
{
if (ferror(fpin))
{
fprintf(stderr, "Reading line %zu failed.\n", 2*blocks + 1);
break;
}
}
{
size_t len = strlen(line1);
if (((sizeof line1 - 1) == len) && ('\n' != line1[len]))
{
fprintf(stderr, "Line %zu too long or new-line missing.\n", 2*blocks);
break;
}
}
{
size_t len = strlen(line2);
if (((sizeof line2 - 1) == len) && ('\n' != line2[len]))
{
fprintf(stderr, "Line %zu too long or new-line missing.\n", 2*blocks + 1);
break;
}
}
if (!l2_done)
{
if (EOF == fputs(line2, fpout))
{
fprintf(stderr, "Writing line %zu as line %zu failed.\n", 2*blocks + 1, 2*blocks);
break;
}
}
if (!l1_done)
{
if (EOF == fputs(line1, fpout))
{
fprintf(stderr, "Writing line %zu as line %zu failed.\n", 2*blocks, 2*blocks + 1);
break;
}
}
++blocks;
result = EXIT_SUCCESS;
}
if (EXIT_SUCCESS == result && !ll_done && l2_done)
{
fprintf(stderr, "Odd number of lines.\n");
}
fclose(fpin); /* Perhaps add error checking here as well ... */
fclose(fpout); /* Perhaps add error checking here as well ... */
return result;
}