fscanf函数的功能是从一个流中执行格式化输入,常用是从文件读取内容。这就有一个问题,调用fscanf后,文件位移量会不会自动指向后面的内容呢?下面来做个实验。将下面代码编译出来。
- #include <stdio.h>
- int main( int argc, char* argv[] )
- {
- char szFile[]="test.txt";
- FILE* fp = fopen(szFile, "r");
- if (!fp)
- {
- printf("无法打开文件:%s", szFile);
- return -1;
- }
- while(true)
- {
- int a, b;
- int nReturn = fscanf(fp, "%d %d\n", &a, &b);
- if(EOF == nReturn)
- break;
- if(2 == nReturn) // 因为上面使用两个格式参数,返回两个参数则表示完全成功
- {
- printf("读取数据成功!\n");
- }
- else if(1 == nReturn) // 部分成功
- {
- printf("读取数据部分成功!\n");
- }
- else
- {
- printf("读取数据失败!\n");
- }
- long curpos = ftell(fp); // 获取此时的文件位移量
- printf("文件位移量为:%d\n", curpos);
- }
- return true;
- }
在编译出来的程序的目录下新建一个test.txt文本文字,在文件里输入“1 2”,注意不包括引号。运行程序,结果为:
- 读取数据成功!
- 文件位移量为:3
可见fscanf完全调用成功后,文件位移量会改变。现在在test.txt里的1后面加个f,即“1f 2”,这样后,f就阻断fscanf读取后面的2了。运行程序,结果为:
- 读取数据部分成功!
- 文件位移量为:1
- 读取数据失败!
- 文件位移量为:1
- 读取数据失败!
- 文件位移量为:1
- 读取数据失败!
- 文件位移量为:1
- 读取数据失败!
- ..........
注意,程序最后死循环了。再次修改test.txt文件,将f移到1的前面,即test.txt的文件内容为“f12”,运行程序,结果为:
- 读取数据失败!
- 文件位移量为:0
- 读取数据失败!
- 文件位移量为:0
- 读取数据失败!
- 文件位移量为:0
- 读取数据失败!
- 文件位移量为:0
- .......
注意,程序最后死循环了。经过上面的实验,可以得出,fscanf在执行完全成功才正确地设置文件位移量,执行部分成功只设置执行成功部分大小的位移量,执行不成功不会设置文件位移量。
如果在程序里使用fscanf来循环读取文件的内容,并是以行为处理单位的,不特别处理会导致程序死循环。建议使用先fgets来读取一行,再用sscanf来处理读取。当然也可以像下面一样在fscanf执行失败后使用fgets跳过失败的行。
- #include <stdio.h>
- int main( int argc, char* argv[] )
- {
- char szFile[]="test.txt";
- FILE* fp = fopen(szFile, "r");
- if (!fp)
- {
- printf("无法打开文件:%s", szFile);
- return -1;
- }
- while(true)
- {
- int a, b;
- int nReturn = fscanf(fp, "%d %d\n", &a, &b);
- if(EOF == nReturn)
- break;
- if(2 == nReturn) // 因为上面使用两个格式参数,返回两个参数则表示完全成功
- {
- printf("读取数据成功!\n");
- }
- else
- {
- char temp[1024];
- fgets(temp, 1024, fp); // 跳过失败的行
- continue;
- }
- long curpos = ftell(fp); // 获取此时的文件位移量
- printf("文件位移量为:%d", curpos);
- }
- return true;
- }