知识点一:文件的存取过程
缓冲区的目的:提高存储效率磁盘使用寿命
![文件的存取过程](https://img-blog.csdnimg.cn/img_convert/94ea973b6da4b00bb06488b2ea0be10d.png)
知识点二:磁盘文件分类
物理上所有的磁盘文件都是二进制存储,以字节为单位顺序存储
逻辑上的文件分类:
文本文件:基于字符编码的文件,如ASCII、UNICODE等,可以文件编辑器直接打开
二进制文件:基于值编码的文件,数据在内存原样输出到磁盘,需要自己判断或使用特定软件分析数据格式
总结:
(1)译码:文件文件编码基于字符定长,译码容易些。二进制文件编码变长,译码难一些(不同二进制文件格式,有不同的译码方式)
(2)空间利用率:二进制文件用一个比特来代表一个意思(位操作)。文本文件任何一个符号需要一个字节
(3)可读性:文本文件用通用记事本根据几乎可以浏览所有文本文件。二进制文件需要一个具体的文件解码器
知识点三:文件指针
![文件指针1](https://img-blog.csdnimg.cn/img_convert/1b5dda5771cac34e6b79711e400b6f1c.png)
typedef struct
{short level; //缓冲区“满”或“空”的程度unsigned flags; //文件状态标志char fd; //文件描述符unsigned char hold; //如无缓冲区不读取字符short bsize; //缓冲区大小unsigned char *buffer; //数据缓冲区的位置unsigned char *curp; //指针,当前的指向unsigned istemp; //临时文件,指示器short token; //用于有效性检查
}FILE;
注意:不要关心FILE的细节只需要会用FILE定义指针变量就行:FILE *fp=NULL;
C语言有三个特殊的文件指针无需定义,打开直接使用:
(1)stdin:标准输入 默认为当前终端(键盘)
使用的scanf、getchar函数默认从此终端获得数据
(2)stdout:标准输出 默认为当前终端(屏幕)
使用的printf、puts函数默认输出信息到此终端
(3)stderr:标准出错 默认当前终端(屏幕)
当我们程序出错或使用:perror函数时信息打印在此终端
知识点四:打开一个文件
形式:file* fp = null; //定义一个FILE类型的指针接收返回值fp = fopen(文件名,文件使用方式);
参数:文件名:要打开的文件名字,可以包含路径信息文件使用方式:“读”、“写”、“文本”或“二进制”等
返回值:成功返回相应指针,失败返回NULL
知识点五:文件使用方式
1、r:以只读方式打开文件
文件不存在:返回NULL
文件存在:返回文件指针,进行后续读操作
2、w:以只写方式打开文件
文件不存在:以指定文件名创建此文件
文件存在:清空文件内容,进行写操作
若文件打不开(如文件只读),返回NULL
3、a:以追加的方式打开文件(往文件的末尾写入数据)
文件不存在:以指定文件名创建此文件(同w)
文件存在,从文件的结尾处进行写操作
4、+:以可读可写的方式打开
5、b:以二进制的方式打开文件
6、t:以文本的方式打开文件(省略)
知识点六:打开方式的组合形式
模式 | 功能 |
---|---|
r或rb | 以只读方式打开一个文本文件(不创建文件) |
w或wb | 以写方式打开文件(使文件长度截断为0字节,创建一个文件) |
a或ab | 以添加方式打开文件,即在末尾添加内容,当文件不存在时,创建文件用于写 |
r+或rb+ | 以可读、可写的方式打开文件(不创建新文件) |
w+或wb+ | 以可读、可写的方式打开文件(使文件长度为0字节,创建一个文件) |
a+或ab+ | 以添加方式打开文件,打开文件并在未尾更改文件(如果文件不存在,则创建文件) |
知识点七:关闭文件
形式:fclose(文件指针); //文件指针:指向要关闭的文件
返回值:关闭文件成功,返回值为0关闭文件失败,返回值非零
知识点八:文件的读写
1、字节读操作
ch = fgetc(fp); //读一个字节
说明:从指定文件读一个字节赋给ch(以“读”或“读写”方式打开)
文件文件:读到结尾返回EOF
二进制文件:读到文件结尾,使用feof判断结尾
事先本地创建a.text
void test01()
{char buf[127]="";int i = 0;FILE *fp = NULL;//1、 使用fopen打开一个文件获得文件指针fp = fopen("a.txt", "r") ;if(fp == NULL){perror("fopen") ;return ;}//2、对文件的操作while(1){//fgetc调用一次 读取到一个字节 buf[i] = fgetc(fp);if(buf[i] == EOF)//EOF表已经对到文件末尾{break ;}i++;}printf("buf = %s\n",buf);//3、 关闭文件fclose(fp);
}
2、字节写操作
形式:fputc(ch,fp); //写一个字符
说明:把一个ch变量中的值(1个字节)写到指定文件如果输出成功,则返回输出的字节如果输出失败,则返回一个EOF
注意:EOF是在stdio.h文件中定义的符号常量,值为-1
void test01()
{char buf[127] = "";int i = 0;FILE *fp = NULL;//1、 使用fopen打开一个文件获得文件指针fp = fopen("a.txt", "w") ;if(fp == NULL){perror("fopen") ;return ;}//2、使用fputc进行文件的数据写入printf("请输入要写入文件的字符串:") ;fgets(buf,sizeof(buf),stdin) ;//会获取换行符buf[strlen(buf) - 1] = 0;//去掉键盘输入的换行符//将字符串buf中的元素逐个写入文件中while(buf[i] != '\0'){fputc(buf[i],fp);i++;}//3、 关闭文件fclose(fp);
}
3、字符串写操作
fputs("china",fp); //写一个字符串
说明:向指定的文件写一个字符串第一个参数可以是字符串常量,字符串数组名或字符指针字符串末尾的'\0'不会写到文件中
void test01()
{char *buf[] = {"床前明月光\n","疑是地上霜\n"};int n = sizeof(buf)/sizeof(buf[0]);int i = 0;FILE *fp = NULL;//1、 使用fopen打开一个文件获得文件指针fp = fopen("a.txt", "w");if(fp == NULL){perror("fopen");return ;}for(i = 0;i<n;i++){fputs(buf[i],fp);} //3、 关闭文件fclose(fp);
}
4、字符串读操作
获取文件一行的数据
形式:fgets(str,n,fp); //读取一个字符串
说明:从fp指向的文件读入n-1个字符,在读入n-1个字符之前遇到换行符或EOF,读入提前结束,并读取换行符,在最后加一个'\0',str为存放数据的首地址
返回值:成功:返回读到字符串的首元素地址失败:返回NULL
void test01()
{char buf[128] = "";char *path = "a.txt";//int i = 0;FILE *fp = NULL;//1、 使用fopen打开一个文件获得文件指针fp = fopen(path,"r"); //fp = fopen("a.txt","r");//fp = fopen("path","r"); //err打开一个文件名叫"path"而不是path指向的文件名"c. txt"if(fp == NULL){perror("fopen");return ;}while(1){char *ret = NULL; //从文件中读取一行数据 ret = fgets(buf,sizeof(buf),fp);if(ret == NULL)break;printf("%s\n",buf);} //3、 关闭文件fclose(fp);
}
5、块读写
(1)fwrite数据块写操作
使用 fwrite 将数据块写入到文件中
形式:fwrite(buffer,size,count,fp);
参数说明:buffer:指向存储数据空间的首地址的指针size:一次写的数据块大小count:要写的数据块个数fp:指向要进行写操作的文件指针
返回值:实际写的数据块数(不是总数据大小)
typedef struct
{char name[16]; //姓名int deff; //防御int atk; //攻击
}HERO;
void test01()
{HERO hero[] = {{"德玛西亚",80,60},{"盲僧",90,80},{"小法", 40,85},{"小炮",50,90}};char *path = "a.txt";//int i = 0;int n = sizeof(hero)/sizeof(hero[0]);FILE *fp = NULL;//1、 使用fopen打开一个文件获得文件指针fp = fopen(path,"w");if(fp == NULL){perror("fopen");return ;}//fwrite将内存的数据原样的输出到文件中//写入文件的数据不便于用户查看但是不会影响程序的读fwrite(hero,sizeof(HERO),n,fp); //3、 关闭文件fclose(fp);
}
(2)fread数据块读操作
使用 fread 从文件中读取数据块
形式:fread(buffer,size,count,fp);
参数说明:buffer:指向存储数据空间的首地址的指针size:一次读的数据块大小count:要读的数据块个数fp:指向要进行读操作的文件指针
返回值:实际读的数据块数(不是总数据大小)
typedef struct
{char name[16]; //姓名int deff; //防御int atk; //攻击
}HERO;
void test01()
{HERO hero[4]= {""};char *path = "a.txt";int i = 0;FILE *fp = NULL;//1、 使用fopen打开一个文件获得文件指针fp = fopen(path,"r");if(fp == NULL){perror("fopen");return ;}fread(hero,sizeof(HERO),4,fp);for(i=0;i<4; i++){//printf(" 英雄姓名:《%s》,防御:%d》, 伤害:《%d》\n",hero[i].name,hero[i].deff,hero[i].atk);printf("英雄姓名:《%s》, 防御:《%d》,伤害:《%d》\n",(hero+i)->name,(hero+i)->deff,(hero+i)->atk);} //3、 关闭文件fclose(fp);
}
6、格式化读操作
读:fprintf(文件指针,格式字符串,输出列表);
typedef struct
{char name[16];//姓名int deff;//防 御int atk;//攻击
}HERO;
void test01()
{HERO hero[]= {{"德玛西亚",80,60},{"盲僧",90,80},{"小法", 40,85},{"小炮",50,90}};char *path = "a.txt";int i = 0;int n = sizeof(hero)/sizeof(hero[0]);FILE *fp = NULL;//1、 使用fopen打开一个文件获得文件指针fp = fopen(path,"w");if(fp == NULL){perror("fopen");return ;}for(i= 0;i<n;i++){fprintf(fp,"英雄:%s 防御:%d 攻击:%d\n",hero[i].name,hero[i].deff,hero[i].atk);} //3、 关闭文件fclose(fp);
}
7、格式化写操作
写:fscanf(文件指针,格式字符串,输入列表);
typedef struct
{char name[16]; //姓名int deff; //防御int atk; //攻击
}HERO;
void test01()
{HERO hero[4]= {""};char *path = "a.txt";int i = 0;//int n = sizeof(hero)/sizeof(hero[0]);FILE *fp = NULL;//1、 使用fopen打开一个文件获得文件指针fp = fopen(path,"r");if(fp == NULL){perror("fopen");return ;}for(i= 0;i<4;i++){fscanf(fp,"英雄:%s 防御:%d 攻击:%d\n", hero[i].name,&hero[i].deff,&hero[i].atk);}for(i=0; i<4; i ++){printf("%s %d %d\n",hero[i].name,hero[i].deff,hero[i].atk);}//3、 关闭文件fclose(fp);
}
注意:
(1)用fprintf和fscanf函数对磁盘文件读写使用方便,但在输入时要将ASCII码转换成二进制形式,在输出时将二进制形式转换成字符,花费时间较多
(2)在内存与磁盘频繁交换数据的情况下,最好不用fprintf和fscanf函数,而用fread和fwrite函数
8、文件随机读写
void test01()
{char buf[128] ="";char *path = "a.txt";int i = 0;//int n = sizeof(hero)/sizeof(hero[0]);FILE *fp = NULL;//1、 使用fopen打开一个文件获得文件指针fp = fopen(path,"w+");if(fp == NULL){perror("fopen");return ;}//先往文件中写入一个字符串"hello file"fputs("hello file",fp);fclose(fp);//重新打开文件让文件的流指针 回到文件首部fp = fopen(path,"r");//在从文件找那个读取该字符串 fgets(buf,sizeof(buf),fp);printf("buf = %s\n",buf); //3、关闭文件fclose(fp);
}
如果在写的步骤中没有关闭后再打开文件则会读取到右边等的情况
所以需要文件写完后需要关闭文件然后重新打开文件,让文件流指针指向文件开始位置让变下次的文件读操作
![结果](https://img-blog.csdnimg.cn/img_convert/f3af7b1a637d9d0535b08437976b1f30.png)
9、复位文件流指针
形式:rewind(文件指针);
功能;把文件内部的位置指针移到文件开始位置
void test01()
{char buf[128] ="";char *path = "a.txt";FILE *fp = NULL;//1、 使用fopen打开一个文件获得文件指针fp = fopen(path,"w+");if(fp == NULL){perror("fopen");return;}//先往文件中写入一个字符串"hello file"fputs("hello file",fp);//复位文件流指针rewind(fp); //在从文件找那个读取该字符串 fgets(buf,sizeof(buf),fp);printf("buf = %s\n",buf); //3、 关闭文件fclose(fp);
}
10、获得文件流指针距离文件首部的字节数
形式:ftell(文件指针);
返回值:返回当前位置(距离文件起始位置的字节数),出错返回-1
void test01()
{char buf[128] = "";char *path = "a.txt";long file_len = 0;FILE *fp = NULL;//1、 使用fopen打开一个文件获得文件指针fp = fopen(path,"w+");if(fp == NULL){perror("fopen");return;}//先往文件中写入一个字符串"hello file"fputs("hello file",fp);//获取文件流指针距离文件首部的字节数file_len = ftell(fp);printf("file_len = %ld\n",file_len); //3、关闭文件fclose(fp);
}
11、定位文件的流指针 fseek函数
形式:fseek(文件类型指针,位移量,起始点); //一般用于二进制文件
功能:移动文件中位置指针的位置
参数说明:位移量:相对 起始点 的偏移量,向前、向后移动的字节数(-10往左边移动10字节,+10往右边移动10字节)起始点:开始添加偏移 位移量 的位置位置指针的位置说明:在文件开头:0 (SEEK_SET)在文件当前位置:1 (SEEK_CUR)在文件末尾:2 (SEEK_END)
一次性读取文件总数
void test01()
{char *file_data = NULL;long file_len = 0;char *path = "a.txt";FILE *fp = NULL;//1、 使用fopen打开一个文件获得文件指针fp = fopen(path,"r");if(fp == NULL){perror("fopen");return ;}//需求:一次性的将文件数据读取到内存中//1、得到文件的总大小//a、 使用 fseek 将文件指针定位到文件尾部fseek(fp,0,2);//b、使用 ftell 计算文件的偏移量==文件的总大小file_len = ftell(fp);//c、使用rewind复位文件流指针rewind(fp);//2、根据文件的总大小合理申请内存空间file_data = (char *)calloc(1,file_len+1); //+1的目的 内存末尾存放'\0' if(file_data == NULL){fclose(fp);return;}//3、一次性将文件数据读入到内存空间fread(file_data,file_len,1,fp);//4、遍历读取到的文件内容printf("file_len = %ld\n",file_len);printf("%s\n",file_data);//5、释放堆区空间if(file_len != NULL){free(file_len);file_len = NULL;} // 关闭文件fclose(fp);
}
知识点九:feof()函数判断文件是否到达文件末尾
EOF宏:只能用于文本文文件
feof函数:可以用于文本文文件 二进制文件
判断文件是否结束:0:未结束,非0:表示结束
void test01()
{ char *path = "a.txt";int i = 0;FILE *fp = NULL;//1、 使用fopen打开一个文件获得文件指针fp = fopen(path,"r");if(fp == NULL){perror("fopen");return ;}//feof(fp)判断文件是否结束 0:未结束,非 0:表示结束//while(feof(fp) == 0)//文件未结束才循环while( !feof(fp)){char ch = fgetc(fp);printf("%c",ch);}// 关闭文件fclose(fp);
}
知识点十:文件加密器
加密过程:
![加密过程](https://img-blog.csdnimg.cn/img_convert/43acd2b11ee198b318084baf724ec6a6.png)
解密过程:
![解密过程](https://img-blog.csdnimg.cn/img_convert/c38d0145b2427787ad632a784e829f93.png)