我必须编写一个程序,从一个行接收的文件读取,然后用读取的单词uppercased覆盖它。 这是我的代码
$key1 = 'a';
$key2 = 'b';
$key3 = 'c';
$array[$key1][$key2][$key3] = 'new value';
但是此程序会附加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
。
我哪里错了?谢谢
答案 0 :(得分:3)
您必须使用fseek重置文件位置指示器,因为fscanf会使其前进。像
这样的东西fseek(fd, length_of_read_string, SEEK_CUR);
这允许您以块的形式读取文件,但要做到正确将会很棘手。或者当然将其重置为文件启动,因为您在1 go中读取所有内容:
fseek(fd, 0L, SEEK_SET);
我强烈建议将修改后的数据写入新文件,然后在程序运行后删除初始文件并重命名新文件。这也将解决您的程序的另一个问题,您在处理之前将整个文件读入内存。
答案 1 :(得分:2)
如果您想进行不会改变长度的就地翻译,可以在两个流中打开源文件,然后以锁步方式执行read-chunk,write-chunk。这样做的好处是可以非常容易地转换为非就地版本,也可以使用不可搜索的文件(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会倾向于认为你的意思是&#34;文件描述符&#34;。 FILE
是文件描述符周围的struct
。文件描述符只是int
,您可以使用原始系统调用进行FILE访问。 FILE
流是文件描述符之上的抽象层 - 它们不是文件描述符。
答案 2 :(得分:0)
当您从文件中读取时,其内部位置指示器会被移动。一旦你开始写作,你就开始从那个位置开始写,这恰好在文件的末尾。因此,您可以有效地将数据附加到文件中。
在写入文件之前,回放手柄以重置位置指示器:
rewind(fp);
在旁注中,您正在错误地读取文件:
while(!feof(fd))
{
fscanf(fd,"%s",buffer[i]);
i++;
}
当你到达文件的末尾时,fscanf将返回错误而不会读取任何内容,但仍然会增加变量i
,就像读取成功一样。然后 你检查feof()是否有文件结尾,但是i
已经增加了。
在调用fscanf()后立即检查feof()和返回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];
答案 3 :(得分:-2)
欢迎使用StackOverflow!
使用带有“w”参数的fopen重新打开流:
fd=fopen(file, "w");
它打开文件,如果文件中有任何内容,则清除它们。