注意以下文件操作中,文件均已创建
1.为什么使用文件
程序运行时的读写的数据保存在内存里,一旦小程序结束,数据会被回收。若有文件,程序在运行时,信息储存在内存中,从内存中读取数据并把数据保存到磁盘上,即数据保存到文件中,可持久保存下来。
2.什么是文件
磁盘上的文件就是文件。
文件分为两种 程序文件(包括源文件,目标文件,exe可执行程序)与数据文件(文件的内容,程序运行时从中读取或输出的内容)(从文件功能分类)
本次讨论数据文件
文件名:一个文件要有一个唯一的文件标识,以便用户识别引用,文件路径+文件名主干+文件后缀
3.文件的打开与关闭
文件的操作:
1.文件打开 2.文件操作(读写) 3.文件关闭
在缓冲文件系统中,文件的概念是“文件类型指针”简称文件指针
每一个被使用的文件都会在内存中开辟了一个对应的信息区,用来存放文件信息(包括文件名,文件内容等)。
可理解为创建了一个文件指针型的结构体变量,该信息就保存在结构体变量中。该类型指针也会维护该信息区
不同的c编译器对FILE类型包括的内容大同小异。
创建FILE型的指针变量FILE*fp;
打开与关闭
文件信息区规定使用fopen与fcloae来打开与关闭文件。
文件使用方式
文件打开fopen
函数参数为(文件名,文件打开方式),返回类型为文件指针型,也是流。
在C语言中文件打开方式有这么几种:
r :以只读方式打开文件,只能读不能写,往文件中写是没有任何效果的。
r+ :可以读,也可以写,文件打开的时候,指向文件开头,可以通过seek改变读写位置。
w :建立供写入的文件,这种方式打开的文件句柄,只能写,如果文件存在则将长度清零,否则新建文件。
w+ :建立用于更新数据文件,如果已存在就抹去原有数据。同w选项,只不过多了一个可读功能;
a :打开或建立一个把数据追加到文件尾的文件。
a+ :同a选项,多了可读的功能。
fclose文件关闭
关闭文件,参数为文件型指针,返回类型为整形,返回成功return 0,否则返回EOF(-1).
这里还需注意,在完成关闭文件后,需要对文件指针置空,否则该指针就是一个野指针。
举一个文件打开与关闭的实例
#include<stdio.h> int main() { //相对路径 FILE* fp = fopen("text.txt","w");//w打开会清清除原文件的内容 //绝对路径 //整个文件的路径 //FILE*fp=fopen("c:\\user\\.....text,txt","w") if (fp == NULL) { perror("fopen"); return 1; } //写文件 //关闭文件 fclose(fp); fp = NULL;//指针置空,防止为野指针 return 0; }
在打开文件还需要注意的一点是,所打开的文件的文件名的路径的区别。所谓相对路径,即该文件是放在该源码文件底下的,打开文件时只用书写文件名,程序运行时直接访问,而绝对路径即他的整个路径,你放在哪里,文件打开就打开哪里的文件,不过路径是完整的。
还需要注意一点如果是绝对路径,注意拷贝来的地址是由转义字符的,在转义字符处加上\,取消转义。才能正确访问该路径。
4.文件的顺序读写
文件的读取输出函数有许多,这里介绍几个。
写字符函数fputc
函数参数为(写入的字符,文件指针),返回类型为
这里注意,每执行一次fputc函数,指针所指向的位置就会往后移动,即再次执行就会直接把写入的下一个字符写到文件里。
读入字符函数 fgetc
可以发现该函数返回的是读取字符的ASCLL码值,参数为文件指针变量。
int main() { FILE* pf = fopen("text.txt","w"); if (pf == NULL) { perror("fopen"); return 1; } //写文件 //把二十六个字母写到文件中 for (int i = 0; i < 26; i++) { fputc('a' + i, pf); } //读文件 //文件末尾隐藏EOF int ch = fgetc(pf);//返回ASCLL码值 一次读一个字符 for (int i = 0; i < 26; i++) { fgetc(pf); } //读取失败会返回EOF printf("%c", ch); fclose(pf); pf = NULL; }
这里举例写入26个字符到文件中,再读取该26个字母到文件中。这里注意的是,函数将文件里的结束标志默认为EOF,遇到EOF函数就会返回。
fscanf 格式化读
这里的函数明显看到与上面两个存在区别,首先操作对象是字符串了,其次函数参数里...的这个表示可变参数,即这里的读取数据的参数可以不止一个,这里我将会用结构体举例。
函数参数为(文件指针,读数据的方式,数据)。
fprintf 格式化写
这里fprintf函数写数据到文件中,图片阐述的清晰,不做赘述。但要注意的是这里的函数但数为
(文件指针,写入文件数据的方式,数据的地址) 。
具体见实例:
struct S { int n; float f; char arr[20]; }; int amin() { struct S s = { 100,3.14f,"hello" }; FILE* p = fopen("text,txt", "w"); if (p == NULL) { perror("fclose"); return 1; } //写 fprintf(p, "%d %f %s", s.n, s.f, s.arr); return 0; } int amin() { struct S s = { 0 }; FILE* p = fopen("text,txt", "r"); if (p == NULL) { perror("fclose"); return 1; } //读 fscanf(p,"%d %f %s",&(s.n),&(s.f),&s.arr);//读取文件内容,存放到结构体里 printf("%d %f %s", s.n, s.f, s.arr); return 0; }
以上的函数从刚开始的图片就可以看到标志了他们的输入输出都是所有输入流或所有输出流。
那什么是流呢?
流的概念
流就可想象成水流,可拿可放 ,而 把数据写在文件中, 也可以拿出数据从文件中 , 写入与拿出就像水流一样,既可以流进来,也可以放出去。
假设向文件里写数据 ,向终端里写数据(屏幕),向网络里写数据,向软盘里写数据,外部设备里写数据,,,取图:
把数据 通过一种方式写进这些 设备等,即我们可以抽象的理解数据写到流里面,而流有自己的方式如何把数据写进哪里,如何去写,我们只需负责数据对流的输入,或输出,即写与读。、
由于流的对象有多种,我们把他们这样认识
写文件时候:称作文件流
终端设备-屏幕:标准输出流 stdout
键盘:标准输入流 stdin
屏幕:标准错误流 stderr
一个c语言程序默认会打开三个流(stdout stdin stderr)
而 以上函数是所有的输入流或输出流,因此我们读写数据的方式也可以这样来:
fgetc 从标准输出流读取数据。
int main() { //stdin stdout stderr 都是FILE *类型的 int ch = fgetc(stdin); printf("%c\n", ch);//从屏幕读入数据,并打印 }
fputc 从标准输入流输入数据。
int main() { fputc('a', stdout);//从屏幕输出字符a fputc('b', stdout);//从屏幕输出字符b fputc('b', stdout);//从屏幕输出字符c fputc('d', stdout);//从屏幕输出字符d }
fprintf 从标准输入流输入数据。
struct S { int n; float f; char arr[20]; }; int main() { struct S s = { 100, 3.666, "hehe" }; fprintf(stdout, "%d %f %s", s.n, s.f, s.arr);//读取数据输出到屏幕上 }
fgets从标准输出流读取数据。
int main() { struct S s = { 0 }; fscanf(stdin, "%d %f %s", &s.n, &s.f, s.arr);//输入数据到屏幕上并赋值给结构体成员 fprintf(stdout, "%d %f %s", s.n, s.f, s.arr);//读取数据输出到屏幕上 return 0; }
其外还有一组函数sprintf与sscanf;
sprintf 格式化数据转化为字符串
sscanf 将字符串转化为格式化数据
struct S { int n; float f; char arr[20]; }; int main() { struct S s = { 200,3.5f,"hello" }; //把结构体变成字符串 char arr[200] = { 0 }; sprintf(arr, " %d %f %s",s.n, s.f, s.arr); printf("%s\n",arr); //把一个字符串转换成格式化数据 struct S tmp = { 0 }; sscanf(arr, "%d %f %s", &(tmp.n), &(tmp.f), tmp.arr); printf("%d %f %s", tmp.n, tmp.f, tmp.arr); return 0; }
三组函数对比
了解完后我们来对比三组函数
对比一组函数
输入函数
scanf 针对标准输入流的 stdin
fscanf 针对所有的输入流(文件流 stdin 等)
sprintf 把一个格式化的数据转化成字符串
对比输出函数
print 针对标准输出流 stdout
fprintf(针对所有输出流)(文件流 stdout 等)
sscanf 把字符串转换为格式化数据