2015-07-11 131 views
2

我必须编写一个程序从一个文件中读取一行文件,然后用读取的文字大写来覆盖它。 这是我的代码fwrite()追加而不是写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。 我在哪里错了?谢谢

回答

3

您必须使用fseek来重置文件位置指示器,因为fscanf会将其前进。类似于

fseek(fd, length_of_read_string, SEEK_CUR); 

这使您能够以块读取文件,但要正确地读取文件会非常棘手。或者,当然它复位到文件的开始,因为你读1转到一切:

fseek(fd, 0L, SEEK_SET); 

我强烈建议修改后的数据写入到一个新的文件,然后该程序运行后,删除原来的文件并重新命名新的那一个。这也将处理您的程序的另一个问题,您在处理之前将整个文件读入内存。

-2

欢迎来到StackOverflow!

与FOPEN与“W”参数重新开放流:

fd=fopen(file, "w"); 

它打开该文件,如果有任何内容的文件中,它会清除它们。

+0

我试过但没有成功,问题是我忘了使用fseek()或倒带()。谢谢! –

+0

“w”将文件截断为零 – PSkocik

0

从文件读取时,其内部位置指示符会移动。一旦你开始写作,你就开始从那个位置开始写作,这正好在文件的末尾。所以你有效地将数据追加到文件中。

倒带手柄写入到文件之前重置位置指示:

rewind(fp); 

在一个侧面说明,你是不正确读取文件:

while(!feof(fd)) 
{ 
    fscanf(fd,"%s",buffer[i]); 
    i++; 
} 

当你到达文件结束时,fscanf将返回一个错误并且不会读取任何内容,但仍然会增加变量i,就像读取成功一样。然后然后您检查feof()作为文件结束,但i已经增加。

检查FEOF()回报的fscanf()的调用的fscanf后立即():

while(1) 
{ 
    int read = fscanf(fd,"%s",buffer[i]); 
    if(read != 1) 
     //handle invalid read 

    if(feof(fd)) 
     break; 
    i++; 
} 

想想会发生什么,如果字符串的长度超过29个字符和/或文件更长包含30多个字符串。 char buffer[30][30];

+0

谢谢,它工作:) –

2

如果您想要进行不改变长度的就地转换,则可以在两个流中打开源文件,然后以锁步形式执行读取块和写入块。这样做的好处是可以非常容易地转换为非原生版本,它也可以处理不可查找的文件(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; }行应返回,你就完蛋了,除非你有该文件的备份副本。 :)


注: 你不应该命名您的FILE指针fd因为C的人往往会觉得你的意思是“文件描述符”。 FILE是围绕文件描述符的struct。文件描述符只是一个int,您可以将其用于原始系统调用的FILE访问。 FILE是文件描述符之上的抽象层 - 它们不是文件描述符。