fscanf函数的功能是从一个流中执行格式化输入,常用是从文件读取内容。这就有一个问题,调用fscanf后,文件位移量会不会自动指向后面的内容呢?下面来做个实验。将下面代码编译出来。

  1. #include <stdio.h> 
  2.  
  3. int main( int argc, char* argv[] ) 
  4.     char szFile[]="test.txt"
  5.     FILE* fp = fopen(szFile, "r"); 
  6.     if (!fp) 
  7.     { 
  8.         printf("无法打开文件:%s", szFile); 
  9.         return -1; 
  10.     } 
  11.     while(true
  12.     { 
  13.         int a, b; 
  14.         int nReturn = fscanf(fp, "%d %d\n", &a, &b); 
  15.         if(EOF == nReturn) 
  16.             break
  17.         if(2 == nReturn)      // 因为上面使用两个格式参数,返回两个参数则表示完全成功 
  18.         { 
  19.             printf("读取数据成功!\n"); 
  20.         } 
  21.         else if(1 == nReturn)         // 部分成功 
  22.         { 
  23.             printf("读取数据部分成功!\n"); 
  24.         } 
  25.         else 
  26.         { 
  27.             printf("读取数据失败!\n"); 
  28.         } 
  29.         long curpos = ftell(fp);       // 获取此时的文件位移量 
  30.         printf("文件位移量为:%d\n", curpos); 
  31.     } 
  32.     return true

在编译出来的程序的目录下新建一个test.txt文本文字,在文件里输入“1 2”,注意不包括引号。运行程序,结果为:

  1. 读取数据成功! 
  2. 文件位移量为:3 

可见fscanf完全调用成功后,文件位移量会改变。现在在test.txt里的1后面加个f,即“1f 2”,这样后,f就阻断fscanf读取后面的2了。运行程序,结果为:

  1. 读取数据部分成功! 
  2. 文件位移量为:1 
  3. 读取数据失败! 
  4. 文件位移量为:1 
  5. 读取数据失败! 
  6. 文件位移量为:1 
  7. 读取数据失败! 
  8. 文件位移量为:1 
  9. 读取数据失败! 
  10. ..........

注意,程序最后死循环了。再次修改test.txt文件,将f移到1的前面,即test.txt的文件内容为“f12”,运行程序,结果为:

  1. 读取数据失败! 
  2. 文件位移量为:0 
  3. 读取数据失败! 
  4. 文件位移量为:0 
  5. 读取数据失败! 
  6. 文件位移量为:0 
  7. 读取数据失败! 
  8. 文件位移量为:0 
  9. .......

注意,程序最后死循环了。经过上面的实验,可以得出,fscanf在执行完全成功才正确地设置文件位移量,执行部分成功只设置执行成功部分大小的位移量,执行不成功不会设置文件位移量。

如果在程序里使用fscanf来循环读取文件的内容,并是以行为处理单位的,不特别处理会导致程序死循环。建议使用先fgets来读取一行,再用sscanf来处理读取。当然也可以像下面一样在fscanf执行失败后使用fgets跳过失败的行。

  1. #include <stdio.h> 
  2.  
  3. int main( int argc, char* argv[] ) 
  4.     char szFile[]="test.txt"
  5.     FILE* fp = fopen(szFile, "r"); 
  6.     if (!fp) 
  7.     { 
  8.         printf("无法打开文件:%s", szFile); 
  9.         return -1; 
  10.     } 
  11.     while(true
  12.     { 
  13.         int a, b; 
  14.         int nReturn = fscanf(fp, "%d %d\n", &a, &b); 
  15.         if(EOF == nReturn) 
  16.             break
  17.         if(2 == nReturn)      // 因为上面使用两个格式参数,返回两个参数则表示完全成功 
  18.         { 
  19.             printf("读取数据成功!\n"); 
  20.         } 
  21.         else 
  22.         { 
  23.             char temp[1024]; 
  24.             fgets(temp, 1024, fp);     // 跳过失败的行 
  25.             continue
  26.         } 
  27.         long curpos = ftell(fp);       // 获取此时的文件位移量 
  28.         printf("文件位移量为:%d", curpos); 
  29.     } 
  30.     return true