提问人:kang kang 提问时间:9/15/2023 更新时间:9/15/2023 访问量:50
读取文件中的一行后如何更改一行?
How to change a line after read a line in file?
问:
这是我的代码。阅读一行并更改它。
char buf[SIZE];
while (fgets(buf,SIZE,fp) != NULL)
{
to_upper(buf);
fseek(fp,-1L,SEEK_CUR);
fputs(buf,fp);
fseek(fp,1L,SEEK_CUR);
}
我知道我可以创建另一个文件来实现,我想知道为什么代码不起作用?
答:
2赞
Jonathan Leffler
9/15/2023
#1
正如我在评论中指出的,您需要在调用之前捕获当前的读取位置;然后,您重置该位置并写入修改后的数据,并且在写入后需要某种搜索,以便可以再次读取。fgets()
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void to_upper(char *buffer)
{
unsigned char u;
while ((u = *buffer) != '\0')
*buffer++ = toupper(u);
}
int main(int argc, char **argv)
{
const char *fname = "input.txt";
if (argc > 2)
{
fprintf(stderr, "Usage: %s [file]\n", argv[0]);
exit(EXIT_FAILURE);
}
if (argc == 2)
fname = argv[1];
FILE *fp = fopen(fname, "r+");
if (fp == NULL)
{
fprintf(stderr, "%s: failed to open file '%s' for read/write: %d %s\n",
argv[0], fname, errno, strerror(errno));
exit(EXIT_FAILURE);
}
char buffer[1024];
long pos = ftell(fp);
while (fgets(buffer, sizeof(buffer), fp) != 0)
{
to_upper(buffer);
fseek(fp, pos, SEEK_SET);
fputs(buffer, fp);
fseek(fp, 0, SEEK_CUR);
pos = ftell(fp);
}
fclose(fp);
return 0;
}
打开成功后的错误检查是不存在的,但在此之前的检查对于安全操作至关重要。
C 标准 §7.21.5.3 fopen
函数 ¶7 说:
当使用更新模式打开文件时(“”作为上述模式参数值列表中的第二个或第三个字符),可以对关联的流执行输入和输出。但是,输出不应直接跟在输入后面,除非对函数或文件定位函数(、、或)进行干预调用,并且输入不能直接跟在输出后面,除非输入操作遇到文件末尾。
+
fflush
fseek
fsetpos
rewind
所示代码在写入后和下次读取之前谨慎使用“no-op”调用。fseek(fp, 0, SEEK_CUR)
1赞
Craig Estey
9/15/2023
#2
几个问题......
- 我们需要记住每条线的前后位置。做一个逐个字符的位置是行不通的。那是因为我们正在阅读一整行(长度不一)。
fseek
- 虽然我们可以在这种特殊情况下这样做,但这有点危险。最好只是做.
fputs
fputc
- 请注意,代码之所以有效,是因为这样做需要一个,但在这里我们这样做不需要。
read/seek/write
fflush
read/seek/write/seek
fflush
下面是重构后的代码。它被注释:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int
main(int argc,char **argv)
{
char buf[10000];
--argc;
++argv;
if (argc != 1) {
fprintf(stderr,"need filename\n");
exit(1);
}
FILE *fp = fopen(*argv,"r+");
if (fp == NULL) {
perror(*argv);
exit(1);
}
long posbef = 0;
while (1) {
// get a line
if (fgets(buf,sizeof(buf),fp) == NULL)
break;
// get starting position of next line
long posaft = ftell(fp);
// get first char of line and convert to uppercase
int chr = buf[0];
chr = toupper((unsigned char) chr);
// seek [back] to start of current line
fseek(fp,posbef,SEEK_SET);
// output updated character
fputc(chr,fp);
// ensure the char is output (?)
// need fflush after an output and before an input
#if 0
fflush(fp);
#endif
// seek to the start of the next line
fseek(fp,posaft,SEEK_SET);
// this is now the start position of the current line for the next
// loop iteration
posbef = posaft;
}
fclose(fp);
return 0;
}
下一个:fseek 操作的复杂性
评论
fflush(fp)
fgets()
fread()/fwrite()