本文继续上一篇文件操作内容并继续其编号。
七、函数fgetc()、getc()
这两个函数的功能都是从文件中读取一个字符,区别进在于 fgetc 是函数而 getc 是宏,宏的执行速度要快一些。使用方法完全一样,二者的原型都定义在stdio.h中。
使用格式:fgetc(参1); getc(参1);
参1:文件指针
返回值:返回值为int类型,读取成功返回读取到的字符;失败返回-1。
说明:
a.需要注意的是这两个函数(宏)的返回值是 int 型的,当然int和char没有本质区别,可以理解成char就是8字节的int,所以返回值可以直接当做char使用。
b.实际中,数据很少是有单个字符组成的,因此每次读取一个字符的实际意义不大,好在每读一次,指针都会相应移动,若要读取多个字符,利用循环即可;说到循环如何退出就用到了《文件操作(一)》中提到的文件末尾标志宏EOF。
八、函数fputc(),putc()
这两个函数(宏)的功能是向文件中写入一个字符,其它情况与前面刚刚介绍的两个函数一样,其定义也是在stdio.h中。
使用格式:fputc(参1, 参2); putc(参1, 参2);
参1:待写入的字符()
参2:文件指针
返回值:写入成功时,两个函数返回写入的字符;写入失败时,返回 EOF(-1)。
九、函数fprintf()
fprintf()有点似曾相识,比我们常用的屏幕显示函数多了一个"f"。实际上,还真是差不多。"f"代表文件,fprintf的功能就是将字符串写入文件。fprintf的原型定义在头文件 stdio.h 。
使用格式:fprintf(参1, 参2, 参3);
参1:文件指针(指向待写入文件)
参2:占位符字符串(如参2为字符串常量,则参3不需要)
参3:与占位符对应的变量(多个变量之间逗号隔开)
返回值:写入成功返回写入的字符数,失败返回-1。
说明:
a. 和printf函数一样,如果写入的是字符串常量,不需要用到占位符,则也用不到参3。
b. 参3不一定都是变量,与占位符匹配的具体值也可以。
c. 如果把文件指针写成代表屏幕的stdout,则这个函数与printf功能相同。
十、函数fscanf()
fscanf函数可以按照占位符指定的模式从文件中读取对应数据并传递给变量;这个函数也定义在头文件stdio.h中。
使用格式:fscanf(参1,参2,参3);
参1:文件指针
参2:占位符字符串
参3:与占位符匹配的接收变量地址(多个变量地址间逗号隔开)
返回值:读取成功,返回完成赋值的变量个数;如果赋值失败则返回-1。
说明:
a. 与scanf函数的要求一样,接收变量必须是指针类型,所以需要取址或者直接用指针变量接收。
b. 使用fscanf函数,必须事先知道文件中的数据结构,否则乱读一气,无法解析出有用数据。
c. 每调用一次fscanf函数,文件内部指针都会相应移动,所以循环调用,可以一直读到文件末尾。
d. 数据之间的间隔可以使用空格、换行符等隔开,这也意味着空格不会作为数据读入。
十一、函数 fgets()
fgets函数用于从文件中读取指定长度的字符串,这个函数的原型定义在stdio.h中。fgets()在读取到指定长度减1个字符之后,或者是遇到换行符、或者遇到文件结尾(EOF)会停止读取。停止读取的条件要记住,用得着。
使用格式:fgets(参1, 参2, 参3);
参1:字符串指针用于存储读取到的字符串;
参2:指定读取的长度(实际读取长度应减去1,因为字符串结尾都要有"\0")
参3:文件指针(指向要读取的文件)
返回值:读取成功时,返回它的第一个参数(字符串指针变量);失败返回空指针NULL。
说明:
a.再次强调,实际读取长度比指定长度少一个字符,该位置用于放置"\0",实际数据长度应短于指定长度至少一个字符。
b.空格、\n(换行符)都可以被读取到并赋值到变量中;但读取到"\n"后虽未达到规定读取字符个数,但也停止读取。
c.读取到字符串结束符"\0"时,读取也会停止,"\0"不会被赋值到变量中,字符串变量中最后"\0"是自动加上的。
d.数据文件中的结构应提前掌握,指定长度与其匹配,否则读取出来形不成有效数据。
e.该函数也可用于循环读取。实际上与文件读写相关的函数,其内部指针都是随着读写动作移动的,因此都可以与循环结构结合起来使用;一个循环读一行,一行一行读下去,直至遇到EOF结束。
f.当我们将指定读取长度定义的足够长时,那每读取一次就可以读到一整行;读到一整行后,赋给一个变量,我们在程序中解析这个变量以获取到有用的数据,这种方法用处很大。
十二、函数 fputs()
fputs()函数用于向文件写入字符串,其原型定义在stdio.h。
使用格式:fputs(参1, 参2);
参1:字符串指针
参2:要写入的文件指针(注意文件打开方式)
返回值:写入成功时返回一个非负整数,写入失败返回-1(EOF)。
说明:
a.字符串中写入的换行符会被写入文件,但不会自动加换行符;
b.字符串结尾的结束符\0不会被写入文件;故意插入的\0后边的内容也不会写入文件,\0后内容会被忽略。
截止到现在,遇到好几组似乎成对出现的读、写函数,它们确实是成对出现的;这些函数较好的使用方式是读取时使用的函数与写入的函数对应起来;当然这也不是绝对的,无论读、写,适应数据结构的需要时第一位的。
十三、将本文学习到的几个函数集中到一个程序案例中,代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
FILE* fp; //文件指针仅定义这一个,需要重定向时使用freopen函数
fp = fopen("temp.txt", "w");
//先进行putc函数写入字符到文件实验
char str[] = "1234567890abcdefghijklmnopqrstuvwxyz";
//写入10个数字和26个小写字母
for (int i = 0; i < 36;i++)
{
putc(str[i],fp); //每次写入一个字符,循环36次全部写入
}
fclose(fp); //用后立即关闭
//此时,若打开temp.txt文件,可以看到写入的数字及字母
//实验getc函数从文件读取字符
if (NULL == freopen("temp.txt", "r", fp)) return 0;
//这个语句的功能就是复用文件指针lp,以只读方式重新打开temp.txt;这里加一个if判断是
//因为如对freopen返回值不处理,代码中会有绿色警告线,实际不管它也无所谓
int ch; //使用int的目的是为了判断可能的负值EOF(-1)
while ((ch = getc(fp)) != EOF)
{
fprintf(stdout,"%c", ch); //利用fprintf函数和stdout指针将从文件读取的字符形式显示到屏幕
}
fclose(fp);
//实验fprintf函数向temp.txt追加写入字符串
if (NULL == freopen("temp.txt", "a", fp)) return 0;
fprintf(fp, "\nC语言从头学要坚持..."); //写入字符串常量仅需两个参数
int a = 10000,b=20000;
fprintf(fp, "\na=%d b=%d\n", a, b); //格式化写入
fclose(fp);
//此时,若打开temp.txt文件,可看到文件中的内容有三行:
//1234567890abcdefghijklmnopqrstuvwxyz
//C语言从头学要坚持...
//a = 10000 b = 20000
//实验用fscanf函数读取文件的字符串
if (NULL == freopen("poem.txt", "rb", fp)) return 0;
//提前准备了内容为古诗词的"poem.txt",文件中有四行诗词,行尾为回车符;重置fp指向该文件。
//说明:使用记事本在电脑上建立的.txt文件,默认字符集为UTF8。我们正学习的函数对于显示UTF8下的英文
//和数字没有问题,但显示汉字却出现乱码。所以用记事本编辑文件保存文件时,可选择"另存为",然后在
//编码中选择ANSI后再保存(ANSI也是所谓的窄字符集)。
char ss[128];
while (fscanf(fp, "%s", ss)== 1) //这里的1不是true,是成功返回的变量数
//如有两个变量,循环条件就是等于2
{
printf("\n%s",ss); //将读取到的字符串显示到屏幕
}
printf("\n");
fclose(fp);
//运行结果:
//白日依山尽,
//黄河入海流,
//欲穷千里目,
//更上一层楼。
//实验fgets读取指定长度的字符串
if (NULL == freopen("table.txt", "rb", fp)) return 0;
//这里准备了一个table.txt文件,里面类似表格结构,包括序号(占6字符)、姓名(9)、年龄(8)、籍贯(16);
//将文件指针fp重置,指向该文件;读取内容后显示到屏幕上
char No[24];
char name[24];
char age[24];
char origin[24];
while (1)
{
if (fgets(No, 6, fp) == NULL) break; //fgets的正常返回值是返回存有读取内容的字符串指针,读取
//失败返回空指针(NULL),以此作为退出循环条件
if (fgets(name, 9, fp) == NULL) break;
if (fgets(age, 8, fp) == NULL) break;
if (fgets(origin, 16, fp) == NULL) break;
printf("%s" , No);
printf("%s", name);
printf("%s", age);
printf("%s", origin);
}
fclose(fp);
//运行结果:
//序号 姓名 年龄 籍 贯
//1 张 三 18 北京市
//2 李四 20 上海市
//3 王五一 35 广东省
//4 李六 28 黑龙江省
//实验函数fputs向文件写入字符串
if (NULL == freopen("temp1.txt", "w", fp)) return 0;
//以写方式新建temp1.txt,并将fp指向该文件
char s1[] = "C语言从头学!\n";
char s2[] = "一定要坚持,\0abcdefg";
char s3[] = "再坚持!";
fputs(s1, fp);
fputs(s2, fp);
fputs(s3, fp);
fclose(fp);
//运行结果:(打开文件查看,内容如下)
//C语言从头学! (换行符被写入,感叹号后换了行)
//一定要坚持,再坚持!(故意插入的结束符及后边内容未被写入,后续再写入内容不换行)
getchar();
return 0;
}