1.认识文件
文件是数据源的一种,最主要的作用是保存数据。
在操作系统中,为了统一对各种硬件的操作,简化接口,不同的硬件设备也都被看成一个文件。对这些文件的操作,等同于对磁盘上普通文件的操作。例如:
通常把显示器称为标准输出文件,printf 就是向这个文件输出数据;
通常把键盘称为标准输入文件,scanf 就是从这个文件读取数据。
操作文件的正确流程为:打开文件 --> 读写文件 --> 关闭文件。文件在进行读写操作之前要先打开,使用完毕要关闭。
所谓打开文件,就是获取文件的有关信息,例如文件名、文件状态、当前读写位置等,这些信息会被保存到一个 FILE 类型的结构体变量中。关闭文件就是断开与文件之间的联系,释放结构体变量,同时禁止再对该文件进行操作。
在C语言中,文件有多种读写方式,可以一个字符一个字符地读取,也可以读取一整行,还可以读取若干个字节。文件的读写位置也非常灵活,可以从文件开头读取,也可以从中间位置读取。
c语言文件的扩展名有:
1.c源文件,函数定义
2.dll动态链接库
3.lib静态链接库
4.dsp,.dsw都是工程文件
5.cpp是C++的源文件
6.so 动态库文件
7.a静态库文件
8
2,文件的打开与关闭
在C语言中,操作文件之前必须先打开文件;所谓“打开文件”,就是让程序和文件建立连接的过程。
打开文件之后,程序可以得到文件的相关信息,例如大小、类型、权限、创建者、更新时间等。在后续读写文件的过程中,程序还可以记录当前读写到了哪个位置,下次可以在此基础上继续操作。
标准输入文件 stdin(表示键盘)、标准输出文件 stdout(表示显示器)、标准错误文件 stderr(表示显示器)是由系统打开的,可直接使用。
使用 <stdio.h> 头文件中的 fopen() 函数即可打开文件,它的用法为:
1.FILE *fopen(char *filename, char *mode);
filename为文件名(包括文件路径),mode为打开方式,它们都是字符串
fopen()文件打开函数介绍:
fopen() 会获取文件信息,包括文件名、文件状态、当前读写位置等,并将这些信息保存到一个 FILE 类型的结构体变量中,然后将该变量的地址返回。
FILE 是 <stdio.h> 头文件中的一个结构体,它专门用来保存文件信息。我们不用关心 FILE 的具体结构,只需要知道它的用法就行。
如果希望接收 fopen() 的返回值,就需要定义一个 FILE 类型的指针。例如:
1.FILE *fp = fopen(“demo.txt”, “r”);
表示以“只读”方式打开当前目录下的 demo.txt 文件,并使 fp 指向该文件,这样就可以通过 fp 来操作 demo.txt 了。fp 通常被称为文件指针。
再来看一个例子:
FILE *fp = fopen(“D:\demo.txt”,“rb+”);
表示以二进制方式打开 D 盘下的 demo.txt 文件,允许读和写。
判断文件是否打开成功
打开文件出错时,fopen() 将返回一个空指针,也就是 NULL,我们可以利用这一点来判断文件是否打开成功,请看下面的代码:
1.FILE *fp;
2.if( (fp=fopen("D:\\demo.txt","rb") == NULL ){
3. printf("Fail to open file!\n");
4. exit(0); //退出程序(结束程序)
5.}
我们通过判断 fopen() 的返回值是否和 NULL 相等来判断是否打开失败:如果 fopen() 的返回值为 NULL,那么 fp 的值也为 NULL,此时 if 的判断条件成立,表示文件打开失败。
fclose()文件关闭函数介绍:
文件一旦使用完毕,应该用 fclose() 函数把文件关闭,以释放相关资源,避免数据丢失。fclose() 的用法为:
1 int fclose(FILE *fp);
fp 为文件指针。例如:
1 fclose(fp);
文件正常关闭时,fclose() 的返回值为0,如果返回非零值则表示有错误发生。
3,文件的随机读写
文件定位函数rewind和fseek
移动文件内部位置指针的函数主要有两个,即 rewind() 和 fseek()。
rewind() 用来将位置指针移动到文件开头,前面已经多次使用过,它的原型为:
1 void rewind ( FILE *fp );
fseek() 用来将位置指针移动到任意位置,它的原型为:
1 int fseek ( FILE *fp, long offset, int origin );
参数说明:
(1)fp 为文件指针,也就是被移动的文件。
(2)offset 为偏移量,也就是要移动的字节数。之所以为 long 类型,是希望移动的范围更大,能处理的文件更大。offset 为正时,向后移动;offset 为负时,向前移动。
(3)origin 为起始位置,也就是从何处开始计算偏移量。C语言规定的起始位置有三种,分别为文件开头、当前位置和文件末尾,每个位置都用对应的常量来表示:
起始点 常量名 常量值
1 文件开头 SEEK_SET 0
2 当前位置 SEEK_CUR 1
3 文件末尾 SEEK_END 2
例如,把位置指针移动到离文件开头100个字节处:
1 fseek(fp, 100, 0);
值得说明的是,fseek() 一般用于二进制文件,在文本文件中由于要进行转换,计算的位置有时会出错。
文件的随机读写
在移动位置指针之后,就可以用前面介绍的任何一种读写函数进行读写了。由于是二进制文件,因此常用 fread() 和 fwrite() 读写。
例子:从键盘输入三组学生信息,保存到文件中,然后读取第二个学生的信息。
1 #include<stdio.h>
2 #define N 3
3 struct stu{
4 char name[10]; //姓名
5 int num; //学号
6 int age; //年龄
7 float score; //成绩
8 }boys[N], boy, *pboys;
9 int main(){
10 FILE *fp;
11 int i;
12 pboys = boys;
13 if( (fp=fopen("d:\\demo.txt", "wb+")) == NULL ){
14 printf("Cannot open file, press any key to exit!\n");
15 getch();
16 exit(1);
17 }
18 printf("Input data:\n");
19 for(i=0; i<N; i++,pboys++){
20 scanf("%s %d %d %f", pboys->name, &pboys->num, &pboys- >age, &pboys->score);
22 }
23 fwrite(boys, sizeof(struct stu), N, fp); //写入三条学生信息
24 fseek(fp, sizeof(struct stu), SEEK_SET); //移动位置指针
25 fread(&boy, sizeof(struct stu), 1, fp); //读取一条学生信息
26 printf("%s %d %d %f\n", boy.name, boy.num, boy.age, boy.score);
27 fclose(fp);
28 return 0;
29 }
运行结果:
1 Input data:
2 Tom 2 15 90.5↙
3 Hua 1 14 99↙
4 Zhao 10 16 95.5↙
5 Hua 1 14 99.000000
4,文件读取结束的判定
持续读取字符,直到读函数返回错误,这时进行feof判断,如果为真,则表示文本文档结束。
1 int feof(FILE *fp);
一,功能为判断文档是否结束,如果已经达到文件尾,返回1,否则返回0.
除此外,部分读函数本身返回值同样可以判断是否结尾。
1 fgets, 返回NULL表示文件结尾。
2 fscanf, fgets等,返回EOF表示=文件结尾。
二,二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
例如:
fread判断返回值是否小于实际要读的个数
二进制
1 #include <stdio.h>
2 enum { SIZE = 5 };
3 int main(void)
4 {
5 double a[SIZE] = {1.0,2.0,3.0,4.0,5.0};
6 double b = 0.0;
7 size_t ret_code = 0;
8 FILE *fp = fopen("test.bin", "wb"); // 必须用二进制模式
9 fwrite(a, sizeof(*a), SIZE, fp); // 写 double 的数组
10 fclose(fp);
11 fp = fopen("test.bin","rb");
12 // 读 double 的数组
13 while((ret_code = fread(&b, sizeof(double), 1, fp))>=1)
14 {
15 printf("%lf\n",b);
16 }
17 if (feof(fp))
18 printf("Error reading test.bin: unexpected end of file\n");
19 fclose(fp);
20 fp = NULL;
21 }
22
文本文件的例子:
1 #include <stdio.h>
2 #include <stdlib.h>
3 int main(void)
4 {
5 int c; // 注意:int,非char,要求处理EOF
6 FILE* fp = fopen("test.txt", "r");
7 if(!fp) {
8 perror("File opening failed");
9 return EXIT_FAILURE;
10 }
11 //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
12 while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
13 {
14 putchar(c);
15 }
16 //判断是什么原因结束的
17 if (feof(fp))
18 puts("End of file reached successfully");
19 fclose(fp);
20 }
5,文件缓存区
文件是指存储在外部存储介质上的、由文件名标识的一组相关信息的集合。由于CPU 与 I/O 设备间速度不匹配。为了缓和 CPU 与 I/O 设备之间速度不匹配矛盾。文件缓冲区是用以暂时存放读写期间的文件数据而在内存区预留的一定空间。使用文件缓冲区可减少读取硬盘的次数。
文件缓冲区是用以暂时存放读写期间的文件数据而在内存区预留的一定空间。通过磁盘缓存来实现,磁盘缓存本身并不是一种实际存在的存储介质,它依托于固定磁盘,提供对主存储器存储空间的扩充,即利用主存中的存储空间, 来暂存从磁盘中读出(或写入)的信息。 主存也可以看做是辅存的高速缓存, 因为,辅存中的数据必须复制到主存方能使用;反之,数据也必须先存在主存中,才能输出到辅存。
一个文件的数据可能出现在存储器层次的不同级别中,例如,一个文件数据通常被存储在辅存中(如硬盘),当其需要运行或被访问时,就必须调入主存,也可以暂时存放在主存的磁盘高速缓存中。大容量的辅存常常使用磁盘,磁盘数据经常备份到磁带或可移动磁盘组上,以防止硬盘故障时丢失数据。有些系统自动地把老文件数据从辅存转储到海量存储器中,如磁带上,这样做还能降低存储价格。
C语言默认会提供缓存机制
缓冲区 分为三种类型:全缓冲、行缓冲和不带缓冲。
1、全缓冲
在这种情况下,当填满标准I/O缓存后才进行实际I/O操作。全缓冲的典型代表是对磁盘文件的读写。
2、行缓冲
在这种情况下,当在输入和输出中遇到换行符时,执行真正的I/O操作。这时,我们输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的I/O操作。典型代表是键盘输入数据。
3、不带缓冲
也就是不进行缓冲,标准出错情况stderr是典型代表,这使得出错信息可以直接尽快地显示出来。
暂时学习到这里,参考了网友的文章,在此表示感谢!