fwrite() 追加而不是写入 C
fwrite() appends instead of write C
我必须编写一个程序 从按行接收的文件中读取,然后用大写的读取单词覆盖它。
这是我的代码
void toUpperCase(char* string) {
int i=0;
while(string[i])
{
string[i]=toupper(string[i]);
i++;
} }
int main(int argc, char** argv) {
if(argc==1)
{
puts("Error: INSERT PATH");
exit(0);
}
char* file=argv[1];
FILE* fd=fopen(file,"r+");
if(fd<0)
{
perror("Error opening file: ");
exit(0);
}
char buffer[30][30];
int i=0;
while(!feof(fd))
{
fscanf(fd,"%s",buffer[i]);
i++;
}
int j=0;
for(j=0; j<i; j++)
{
toUpperCase(buffer[j]);
fwrite(buffer[j],strlen(buffer[j]),1,fd);
}
fclose(fd);
return 0; }
但是这个程序附加了 buffer[][]
中包含的单词而不是覆盖文件。
如果文件包含类似 pippo pluto foo
的内容,那么执行后是 pippo pluto fooPIPPOPLUTOFOO
而不是 PIPPO PLUTO FOO
。
我哪里错了?谢谢
欢迎使用 Whosebug!
使用带 "w" 参数的 fopen 重新打开流:
fd=fopen(file, "w");
它打开文件,如果文件中有任何内容,它会清除它们。
当您从文件中读取时,其内部位置指示器会移动。一旦你开始写,你就从那个位置开始写,恰好在文件的末尾。所以你有效地将数据附加到文件中。
在写入文件之前倒回手柄以重置位置指示器:
rewind(fp);
附带说明一下,您读错了文件:
while(!feof(fd))
{
fscanf(fd,"%s",buffer[i]);
i++;
}
当您到达文件末尾时,fscanf 将 return 出错并且不读取任何内容,但您仍然递增变量 i
,就好像读取成功一样。然后 然后 你检查 feof() 文件结束,但是 i
已经增加了。
调用fscanf()后立即检查fscanf()的feof() 和 return:
while(1)
{
int read = fscanf(fd,"%s",buffer[i]);
if( read != 1 )
//handle invalid read
if( feof(fd) )
break;
i++;
}
想想如果字符串超过 29 个字符会发生什么 and/or 文件包含超过 30 个字符串。 char buffer[30][30];
您必须使用 fseek 重置文件位置指示器,因为 fscanf 会推进它。像
fseek(fd, length_of_read_string, SEEK_CUR);
这允许您分块读取文件,但要正确读取文件会很棘手。或者当然将其重置为文件开头,因为您一次阅读了所有内容:
fseek(fd, 0L, SEEK_SET);
我强烈建议将修改后的数据写入一个新文件,然后程序有运行后,删除初始文件并重命名新文件。这也将解决您的程序的另一个问题,您在处理它之前将整个文件读入内存。
如果您想进行不改变长度的就地翻译,您可以分两个流打开源文件,然后同步读取块、写入块。这样做的好处是非常容易转换为非就地版本,该版本也适用于不可搜索的文件(stdin/stdout、管道和套接字)。
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h> //toupper
inline void upcaseStr(char* str){
for(;*str;str++) { *str=toupper(*str); }
}
int upcaseStream(FILE* in, FILE* out){
char buf[BUFSIZ]; //BUFSIZ is an implementation-defined constant for an optimal buffer size
while(fgets(buf, BUFSIZ, in)){
upcaseStr(buf);
if(fputs(buf, out) == EOF){ return 1; }
}
if(!feof){ return 1; }
return 0;
}
int main(int argc, char **argv)
{
//default in and out
FILE* in = stdin;
FILE* out = stdout;
if(argc == 2) {
in = fopen(argv[1], "r"); //for reading
out = fopen(argv[1], "r+"); //for writing (and reading) starting at the beginning
if(!(in && out)){
fprintf(stderr, "Error opening file %s for reading and writing: %s\n", argv[1], strerror(errno));
}
}
return upcaseStream(in, out);
}
如果您确实使用就地版本,那么在不太可能的情况下 if(fputs(buf, out) == EOF){ return 1; }
行应该 return,除非您有该文件的备份副本,否则您就完蛋了。 :)
注:
你不应该将你的 FILE
指针命名为 fd
,因为 C 人会倾向于认为你的意思是 "file descriptor"。 FILE
是围绕文件描述符的 struct
。文件描述符只是一个 int
,您可以将其用于通过原始系统调用进行文件访问。 FILE
流 是文件描述符之上的抽象层——它们不是文件描述符。
我必须编写一个程序 从按行接收的文件中读取,然后用大写的读取单词覆盖它。 这是我的代码
void toUpperCase(char* string) {
int i=0;
while(string[i])
{
string[i]=toupper(string[i]);
i++;
} }
int main(int argc, char** argv) {
if(argc==1)
{
puts("Error: INSERT PATH");
exit(0);
}
char* file=argv[1];
FILE* fd=fopen(file,"r+");
if(fd<0)
{
perror("Error opening file: ");
exit(0);
}
char buffer[30][30];
int i=0;
while(!feof(fd))
{
fscanf(fd,"%s",buffer[i]);
i++;
}
int j=0;
for(j=0; j<i; j++)
{
toUpperCase(buffer[j]);
fwrite(buffer[j],strlen(buffer[j]),1,fd);
}
fclose(fd);
return 0; }
但是这个程序附加了 buffer[][]
中包含的单词而不是覆盖文件。
如果文件包含类似 pippo pluto foo
的内容,那么执行后是 pippo pluto fooPIPPOPLUTOFOO
而不是 PIPPO PLUTO FOO
。
我哪里错了?谢谢
欢迎使用 Whosebug!
使用带 "w" 参数的 fopen 重新打开流:
fd=fopen(file, "w");
它打开文件,如果文件中有任何内容,它会清除它们。
当您从文件中读取时,其内部位置指示器会移动。一旦你开始写,你就从那个位置开始写,恰好在文件的末尾。所以你有效地将数据附加到文件中。
在写入文件之前倒回手柄以重置位置指示器:
rewind(fp);
附带说明一下,您读错了文件:
while(!feof(fd))
{
fscanf(fd,"%s",buffer[i]);
i++;
}
当您到达文件末尾时,fscanf 将 return 出错并且不读取任何内容,但您仍然递增变量 i
,就好像读取成功一样。然后 然后 你检查 feof() 文件结束,但是 i
已经增加了。
调用fscanf()后立即检查fscanf()的feof() 和 return:
while(1)
{
int read = fscanf(fd,"%s",buffer[i]);
if( read != 1 )
//handle invalid read
if( feof(fd) )
break;
i++;
}
想想如果字符串超过 29 个字符会发生什么 and/or 文件包含超过 30 个字符串。 char buffer[30][30];
您必须使用 fseek 重置文件位置指示器,因为 fscanf 会推进它。像
fseek(fd, length_of_read_string, SEEK_CUR);
这允许您分块读取文件,但要正确读取文件会很棘手。或者当然将其重置为文件开头,因为您一次阅读了所有内容:
fseek(fd, 0L, SEEK_SET);
我强烈建议将修改后的数据写入一个新文件,然后程序有运行后,删除初始文件并重命名新文件。这也将解决您的程序的另一个问题,您在处理它之前将整个文件读入内存。
如果您想进行不改变长度的就地翻译,您可以分两个流打开源文件,然后同步读取块、写入块。这样做的好处是非常容易转换为非就地版本,该版本也适用于不可搜索的文件(stdin/stdout、管道和套接字)。
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h> //toupper
inline void upcaseStr(char* str){
for(;*str;str++) { *str=toupper(*str); }
}
int upcaseStream(FILE* in, FILE* out){
char buf[BUFSIZ]; //BUFSIZ is an implementation-defined constant for an optimal buffer size
while(fgets(buf, BUFSIZ, in)){
upcaseStr(buf);
if(fputs(buf, out) == EOF){ return 1; }
}
if(!feof){ return 1; }
return 0;
}
int main(int argc, char **argv)
{
//default in and out
FILE* in = stdin;
FILE* out = stdout;
if(argc == 2) {
in = fopen(argv[1], "r"); //for reading
out = fopen(argv[1], "r+"); //for writing (and reading) starting at the beginning
if(!(in && out)){
fprintf(stderr, "Error opening file %s for reading and writing: %s\n", argv[1], strerror(errno));
}
}
return upcaseStream(in, out);
}
如果您确实使用就地版本,那么在不太可能的情况下 if(fputs(buf, out) == EOF){ return 1; }
行应该 return,除非您有该文件的备份副本,否则您就完蛋了。 :)
注:
你不应该将你的 FILE
指针命名为 fd
,因为 C 人会倾向于认为你的意思是 "file descriptor"。 FILE
是围绕文件描述符的 struct
。文件描述符只是一个 int
,您可以将其用于通过原始系统调用进行文件访问。 FILE
流 是文件描述符之上的抽象层——它们不是文件描述符。