fscanf 函数用于格式化读入文件中数据,可以大大提高读取文件的效率。这次笔者将最近使用该函数的一些经验记录下来。
int fscanf(file* stream, const char* format, [argument...]);
fscanf 函数与 scanf 函数用法类似,只不过前者用于读取文件流的数据而已。至于 fscanf 的基础用法我就不赘述了,网上的文章很多。简单提及一下要点:
1. format str:如%d, %f, %c, %s等,分别表示读入一个整数,浮点数,字符,字符串。还可以加上控制,如%ld,表示读入一个长整型数,%20s表示最多读入20个字符。2. 返回值:在没有出错的情况下,fscanf 返回正确匹配和赋值的域的个数;如果出错,则返回eof。fscanf 的难点在于以下几点:
1. 对空白符的处理(空格、制表符、换行符);2. *的用法;3. [] 以及 [^] 的用法;4. eof 的处理;对于上述问题,网上的文章都语焉不详,所以笔者自己写了点实验代码进行验证,应该是比较详细的小结了。
先把结论罗列在下面,具体的实验代码放在文章最后:
为了验证上面西安大学排行提出的一些问题,笔者动手写了下面的实验代码进行验证分析,代码共分为六个部分,注意每个部分所使用的文件内容是不一样的:
1. fscanf 对空格的处理;2. fscanf 对制表符的处理;3. fscanf 对换行符的处理;4. 当空格、制表符以及换行符混杂时fscanf的处理;5. []符号在format str中的应用;6. 出错的情况。(注意为了清晰无误地表示出不同的空白符,用 <\b>代表空格,<\t>表示制表符,<\n>表示换行符。)
#include <stdio.h>#include <errno.h>void fscanftest(file* fp) {char c1, c2, s1[100], s2[100];int d;// 第一部分:fscanf对空格的处理printf("the content of file is:\n");printf("hello<\\b>world<\\b><\\b>666lucky<\\n>");printf("\n\n");// %s不会跳过后面的空格fscanf(fp, "%s", s1);printf("%s!\n", s1); // hello!// %s会跳过前面的一个空格rewind(fp); // 将光标移回文件开头fscanf(fp, "%s%s", s2, s1);printf("%s! %s!\n", s2, s1); // hello! world!// %*s会从文件流中读入,但是不会将值赋予变量(*的作用)rewind(fp);fscanf(fp, "%*s%s", s1锻炼计划);printf("%s!\n", s1); // world!// %s会跳过前面的多个空格rewind(fp);fscanf(fp, "%*s%s%s", s2, s1);printf("%s! %s!\n", s2, s1); // world! 666lucky!// %c不会跳过空格rewind(fp);fscanf(fp, "%*s%c", &c1);printf("%c!\n", c1); // " !"// format str中的一个空格表示如果文件流接下来有连续空格,都跳过rewind(fp);fscanf(fp, "%*s%*s %c", &c1);printf("%c!\n", c1); // "6!"rewind(fp);fscanf(fp, "%*s%*s%*d%c", &c1);printf("%c!\n", c1); // "l!" rewind(fp);fscanf(fp, "%*s%*s%*d %c", &c2); // 注意这里format str中的空格没起作用,是因为666和lucky之间没有空白符printf("%c!\n", c2); // "l!"rewind(fp);fscanf(fp, "%*s%*s%*d%s", s1);printf("%s!\n", s1); // "lucky!" rewind(fp);fscanf(fp, "%*s%*s%*d %s", s2);printf("%s!\n", s2); // "lucky!"// format str中的多个连续空格和一个空格的效果是一样的rewind(fp);fscanf(fp, "%*s %c", &c1);printf("%c!\n", c1); // "w!"rewind(fp);fscanf(fp, "%*s %c", &c2);printf("%c!\n", c2); // "w!"// 第二部分:fscanf对制表符的处理printf("the content of file is:\n");printf("hello<\\t>world<\\t><\\t>666lucky<\\n>");printf("\n\n");// %s不会跳过后面的制表符fscanf(fp, "%s", s1);printf("%s!\n", s1); // hello!// %s会跳过前面的一个制表符rewind(fp);fscanf(fp, "%s%s", s2, s1);printf("%s! %s!\n", s2, s1); // hello! world!// %s会跳过前面的多个制表符rewind(fp);fscanf(fp, "%*s%s%s", s2, s1);printf("%s! %s!\n", s2, s1); // world! 666lucky!// %c不会跳过制表符rewind(fp);fscanf(fp, "%*s%c", &c1);printf("%c!\n", c1); // "<\\t>!"// format str中的一个制表符表示如果文件流接下来有连续制表符,都跳过rewind(fp);fscanf(fp, "%*s%*s\t%c", &c1);printf("%c!\n", c1); // "6!"rewind(fp);fscanf(fp, "%*s%*s%*d%c", &c1);printf("%c!\n", c1); // "l!" rewind(fp);fscanf(fp, "%*s%*s%*d\t%c", &c2);printf("%c!\n", c2); // "l!"rewind(fp);fscanf(fp, "%致老师*s%*s%*d%s", s1);printf("%s!\n", s1); // "lucky!" rewind(fp);fscanf(fp, "%*s%*s%*d\t%s", s2);printf("%s!\n", s2); // "lucky!"// format str中的多个连续制表符和一个制表符的效果是一样的rewind(fp);fscanf(fp, "%*s\t%c", &c1);printf("%c!\n", c1); // "w!"rewind(fp);fscanf(fp, "%*s\t\t%c", &c2);printf("%c!\n", c2); // "w!"// 第三部分:fscanf对换行符的处理printf("the content of file is:\n");printf("hello<\\n>world<\\n><\\n>666lucky<\\n>");printf("\n\n");// %s不会跳过后面的换行符fscanf(fp, "%s", s1);printf("%s!\n", s1); // hello!// %s会跳过前面的一个换行符rewind(fp);fscanf(fp, "%s%s", s2, s1);printf("%s! %s!\n", s2, s1); // hello! world!// %s会跳过前面的多个换行符rewind(fp);fscanf(fp, "%*s%s%s", s2, s1);printf("%s! %s!\n", s2, s1); // world! 666lucky!// %c不会跳过换行符rewind(fp);fscanf(fp, "%*s%c", &c1);printf("%c!\n", c1); // "<\\n>!"// format str中的一个换行符表示如果文件流接下来有连续换行符,都跳过rewind(fp);fscanf(fp, "%*s%*s\n%c", &c1);printf("%c!\n", c1); // "6!"rewind(fp);fscanf(fp, "%*s%*s%*d%c", &c1);printf("%c!\n", c1); // "l!" rewind(fp);fscanf(fp, "%*s%*s%*d\n%c", &c2);printf("%c!\n", c2); // "l!"rewind(fp);fscanf(fp, "%*s%*s%*d%s", s1);printf("%s!\n", s1); // "lucky!" rewind(fp);fscanf(fp, "%*s%*s%*d\n%s", s2);printf("%s!\n", s2); // "lucky!"// format str中的多个连续换行符和一个换行符的效果是一样的rewind(fp);fscanf(fp, "%*s\n%c", &c1);printf("%c!\n", c1); // "w!"rewind(fp);fscanf(fp, "%*s\n\n%c", &c2);printf("%c!\n", c2); // "w!"// 第四部分:当空格、制表符以及换行符混杂时fscanf的处理printf("the content of file is:\n");printf("hello<\\b><\\t><\\n>world<\\t><\\b><\\n>666lucky<\\n>");printf("\n\n");// %s会跳过连在一起的空格、制表符和换行符fscanf(fp, "%s%s", s2, s1);printf("%s! %s!\n", s2, s1); // hello! world!// 当作为空白符时,format str中的空格、制表符以及换行符是一样的,可以相互替代!rewind(fp);fscanf(fp, "%*s %c", &c1);printf("%c!\n", c1); // "w!"rewind(fp);fscanf(fp, "%*s\t%c", &c2);printf("%c!\n", c2); // "w!"rewind(fp);fscanf(fp, "%*s\n%c", &c1);printf("%c!\n", c1); // "w!"// 第五部分:[]符号在format str中的应用printf("the content of file is:\n");printf("hello<\\b><\\t><\\n>world<\\b><\\t>666lucky<\\n>");printf("\n\n");// [el]表示只读取'e'或者'l'这个字符,[0-9]表示只读取0-9这10个数字字符// %[]之后的域都不起作用了,不会读取文件流。// test#1: %c%[]s可以正常工作// output#1: h! ell!errno = 0;d = fscanf(fp, "%c%[el]s", &c1, s1);if (d == 2) printf("%c! %s!\n", c1, s1);el {printf("d = %d\n", d);if (errno != 0) perror("fscanf");el printf("error: no matching characters!\n");}// test#2: %[]s后面的%c没有正常读取// output#2: d = 2errno = 0;rewind(fp);d = fscanf(fp, "%c%[el]s%c", &c2, s2, &c1);if (d == 3) printf("%c! %s! %c!\n", c2, s2, c1);el {printf("d = %d\n", d);if (errno != 0) perror("fscanf");el printf("error: no matching characters!\n");}// test#3: %[]s后面的%s没有正常读取// output#3: d = 2errno = 0;rewind(fp);d = fscanf(fp, "%c%[el]s%s", &c1, s1, s2);if (d == 3) printf("%c! %s! %s!\n", c1, s1, s2);el {printf("d = %d\n", d);if (errno != 0) perror("fscanf");el printf("error: no matching characters!\n");}// test#4: 再次运行fscanf函数就可以继续读取文件流// output#4: o! world!errno = 0;d = fscanf(fp, "%c%s", &c2, s2);if (d == 2) printf("%c! %s!\n", c2, s2);el {printf("d = %d\n", d);if (errno != 0) perror("fscanf");els蚂蚁e printf("error: no matching characters!\n");}// [^el]表示不读取'e'也不读取'l'这个字符,[^0-9]表示不读取0-9的数字字符// %[^]之后的域都不起作用了,不会读取文件流。// test#5: %c%[^]s可以正常工作,注意下面的%[^w]s这个域读取了空格、制表符以及换行符。// output#5: h! ello<\\b><\\t><\\n>!errno = 0;rewind(fp);d = fscanf(fp, "%c%[^w]s", &c1, s1);if (d == 2) printf("%c! %s!\n", c1, s1)快乐购物;el {printf("d = %d\n", d);if (errno != 0) perror("fscanf");el printf("error: no matching characters!\n");}// test#6: %[^]s后面的%s没有正常读取// output#6: d = 2errno = 0;rewind(fp);d = fscanf(fp, "%c%[^w]s%s", &c2, s2, s1);if (d == 3) printf("%c! %s! %s!\n", c2, s2, s1);el {printf("d = %d\n", d);if (errno != 0) perror("fscanf");el printf("error: no matching characters!\n");}// test#7: 再次运行fscanf函数就可以继续读取文件流// output#7: w! orld!errno = 0;d = fscanf(fp, "%c%s", &c1, s1);if (d == 2) printf("%c! %s!\n", c1, s1);el {printf("d = %d\n", d);if (errno != 0) perror("fscanf");el printf("error: no matching characters!\n");}// test#8: %[^\n]s可以一直读取到行末尾,哪怕遇到空格或者制表符。// output#8: h! ello<\\b><\\t>!errno = 0;rewind(fp);d = fscanf(fp, "%c%[^\n]s", &c2, s2);if (d == 2) printf("%c! %s!\n", c2, s2);el {printf("d = %d\n", d);if (errno != 0) perror("fscanf");el printf("error: no matching characters!\n");}// test#9: %[^ ]s不会读取空格,但是会读取制表符和换行符// output#9: <\\t><\\n>world!errno = 0;rewind(fp);d = fscanf(fp, "%*s%*c%[^ ]s", s1);if (d == 1) printf("%s!\n", s1);el {printf("d = %d\n", d);if (errno != 0) perror("fscanf");el printf("error: no matching characters!\n");} // test#10: %[^\t]s不会读取制表符,但是会读取空格和换行符// output#10: <\\n>world<\\b>!errno = 0;rewind(fp);d = fscanf(fp, "%*s%*c%*c%[^\t]s", s2);if (d == 1) printf("%s!\n", s2);el {printf("d = %d\n", d);if (errno != 0) perror("fscanf");el printf("error: no matching characters!\n");} // test#11: %[^]s不会跳过前面的空白符// output#11: <\\b><\\t><\\n>wo!errno = 0;rewind(fp);d = fscanf(fp, "%*s%[^r]s", s1);if (d == 1) printf("%s!\n", s1);el {printf("d = %d\n", d);if (errno != 0) perror("fscanf");el printf("error: no matching characters!\n");}// 第六部分:出错的情况// 从第五部分 test#2 以及 test#3 的例子中可以看出,fscanf的返回值表示能够正确赋值的域的个数。如果出错,fscanf返回eof。// 怎样才算出错?如果还没有任何一个域匹配成功或者任何一个匹配失败发生之前,就达到了文件流末尾,就算出错;或者读取文件流出错。就这两种情况。// 即使所有域都不匹配,但只要没到达文件流末尾并且读取文件流过程中没有发生错误,就不算出错,errno就是0。此时,fscanf返回0。printf("the content of file is:\n");printf("hello");printf("\n\n");// test#1: 此时的%c发生匹配失败,所以返回值为0。// output#1: d = 0errno = 0;d = fscanf(fp, "%*s%c", &c1);if (d == 1) printf("%c!\n", c1);el {printf("d = %d\n", d);if (errno != 0) perror("fscanf");el printf("error: no matching characters!\n");} // test#2: 继续读取,已经到达文件流末尾,返回eof。// output#2: d = -1errno = 0;d = fscanf(fp, "%c", &c2);if (d == 1) printf("%c!\n", c2);el {printf("d = %d\n", d);if (errno != 0) perror("fscanf");el printf("error: no matching characters!\n");}}int main(int argc, char* argv[]) {file *fp;if (argc < 2) {printf("usage: %s <filename>\n", argv[0]);return 1;}if ((fp = fopen(argv[1], "r")) == null) {printf("error: cannot open file\n");return 1;}fscanftest(fp);fclo(fp);return 0;}
以上就是详解c语言fscanf函数读取文件示例教程的详细内容,更多关于c语言fscanf读取文件的资料请关注www.887551.com其它相关文章!
本文发布于:2023-04-05 00:56:41,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/ec36e6449b739eb04c874ee5e16546d1.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:详解C语言fscanf函数读取文件教程及源码.doc
本文 PDF 下载地址:详解C语言fscanf函数读取文件教程及源码.pdf
留言与评论(共有 0 条评论) |