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 是文件描述符之上的抽象层——它们不是文件描述符。