想法【可以跳过】:file函数的操作大概就像我们用自己的编译器上面的输入端对记事本进行操作吧,其实我感觉还不如我们直接对记事本进行修改然后保存,hhhh。
------------预备知识----------
1.1数据流
指程序与数据互相是以 ‘流’ 的形式交互的。{程序是计算机操作的依据,数据是计算机操作的对象。}我们在进行fopen打开文件这一项操作的时候,就是在打开数据流,fclose“关闭文件”就是在关闭数据流。
1.2缓冲区(buffer)
就是内存,不过作用是用来缓冲,暂时存放做准备执行的数据,提高执行效率。【内存的存取速度比磁盘驱动器快得多。】
当进行文件读取时,不会直接对磁盘进行读取,而是先打开数据流,将磁盘上的文件信息拷贝到缓冲区内,然后程序再从缓冲区中读取所需数据。
1.3 文件类型:
分为文本文件和二进制文件两种。
文本文件是以字符编码的方式进行保存的。二进制文件将内存中数据原封不至文件中,适用于非字符为主的数据。如果以记事本打开,只会看到一堆乱码。其实,除了文本文件外,所有的数据都可以算是二进制文件。
--------------正文---------------
2.文本文件操作/*主要是关注返回值和函数里面的具体参数*/
2.1相关函数举例:fopen(), fclose(), fgetc(), fputc(), fgets(), fputs(), fprintf(), fscanf()等。
2.2 打开文件
函数原型为:_CRTIMP FILE * __cdecl fopen(const char *, const char *);
第一参数为文件名,第二个参数为打开模式。
打开成功,fopen返回一个结构地址【我们一般用指针fp来存】,否则返回一个NULL。如果没有指定文件路径,则默认为当前工作目录。
FILE *fp;
fp = fopen("c:\\temp\\test.txt", "r") //由于反斜杠\是控制字符,所以必须再加一个反斜杠。左边叫做绝对路径。
fopen是对缓冲区进行操作,fopen关闭时写入磁盘。
打开文件的方式:
"r":只能从文件中读数据,该文件必须先存在,否则打开失败。
"w":只能向文件写数据,若指定的文件不存在则创建它,如果存在则先删除原有内容。
"a":向文件增加新数据(不删除原有数据),若文件不存在则打开失败,打开时位置指针移到文件末尾【a+也是】。
"r+":可读/写数据,该文件必须先存在,否则打开失败
"w+":可读/写数据,用该模式打开新建一个文件,先向该文件写数据,然后可读取该文件中的数据。
"a+":可读/写数据【a只能写不能读】,原来的文件不被删去,位置指针移到文件末尾
以上打开方式前加一个“b”【eg:br,bw】表示对二进制文件进行操作。
2.3关闭文件
函数原型为:_CRTIMP int __cdecl fclose(FILE *);
关闭成功返回值0,否则返回非零值。
注:在执行完文件的操作后,要进行“关闭文件”操作。不然打开过多文件会使计算机速度变慢。
/*打开文件并进行判断和关闭文件*/
FILE *fp;
fp = fopen("c:\\temp\\test.txt", "r");
if(fp)
printf("打开成功\n");
else
{
printf("失败\n");
fclose(fp);
}
2.4字符存取函数
函数原型为:
_CRTIMP int __cdecl fputc(int, FILE *); //将字符逐一写入文件
_CRTIMP int __cdecl fgetc(FILE *);
字符读取函数fgetc()可从文件数据流中一次读取一个字符,然后读取光标移动到下一个字符,并逐步将文件的内容读出。如果字符读取成功,则返回所读取的字符,否则返回EOF【EOF在c语言中表示文件结束符(end of file),以EOF作为文件结束标志的文件,必须是文本文件。】
2.5字符串存取函数
函数原型为:
_CRTIMP int __cdecl fputs(const char *, FILE *);
_CRTIMP char * __cdecl fgets(char *, int, FILE *); //从指定文件读入一个字符串
如:fgets(str, n, fp);
参数n为要求得到的字符个数,但只从fp指向的文件输入n-1个字符,然后在最后加一个'\0'字符,如果在读完n-1个字符之前遇到换行符或EOF,读入结束。
fputs函数的作用是向指定文件输出一个字符串,如:fputs("Hey", fp); fputs函数的第一个参数可以是字符串常量、字符数组名或字符型指针。若输出成功,则返回0,否则返回EOF。
2.6格式化存取函数
函数原型为:
_CRTIMP int __cdecl fprintf(FILE *, const char *, ...);
_CRTIMP int __cdecl fscanf(FILE *, const char *, ...);
{解释一下格式化:fprintf和fscanf与“printf和scanf”差不多都是格式化,还记得嘛,我们用scanf在终端上面写12345,汉字或者其他东西的时候,计算机内部的样子不是我们写进去的,而是计算机的语言,这些函数“格式化”之后转换处理,变成了计算机可以看得懂的语言进行处理,在用printf函数把计算机语言变成我们重新看得懂的内容。}
/*fprintf和fscanf函数的使用*/
#include <stdio.h>
void main()
{
FILE *fp;
int num = 10;
char name[10] = "Leeming";
char gender = 'M';
if((fp = fopen("info.txt", "w+")) == NULL)
printf("can't open the file! \n");
else
fprintf(fp, "%d, %s, %c", num, name, gender); //将数据格式化输出到文件info.txt中
fscanf(fp, "%d, %s, %c", &num, name, &gender); //从文件info.txt中格式化读取数据
printf("%d, %s, %c \n", num, name, gender); //格式化输出到屏幕
fclose(fp);
}
3. 二进制文件操作
3.1 数据块存取函数
函数原型:
_CRTIMP size_t __cdecl fread(void *, size_t, size_t, FILE *);
_CRTIMP size_t __cdecl fwrite(const void *, size_t, size_t, FILE *);
一般形式://第一个参数是地址
fread(&变量, size, count, fp);
fwrite(&变量, size, count, fp);
参数含义:fread//把fp的地址给&变量
fread(地址,每个数据大小【多用sizeof解决】,数据个数 size/sizeof解决,地址);
fwrite相同。
3.2 随机存取函数【也可以叫定位函数】fseek()
函数原型:
_CRTIMP int __cdecl fseek(FILE *, long, int);
能将位置指针按需要移动到任意位置。
形式:
fseek(fp, i*sizeof(Person), 0);
或者
fseek(fp, i*sizeof(Person), SEEK_SET);
0代表文件开始【SEEK_SET】,1代表当前位置【SEEK_CUR】,2代表文件末尾【SEEK_END】。
fseek()函数一般用于二进制文件,因为文本文件要发生字符转换,计算位置时往往会发生混乱。
最后是我默写的代码:
/*FILE文件*/
#include<stdio.h>
#include<stdlib.h>
typedef struct _Person{
char name[20];
char sex[4];
int age;
}Person;
int main()
{
//打开文件,fopen存在计算机里面
FILE* fp=fopen("D:\\计算机dev.c++\\c语言FILE\\test.txt","r+");//这是绝对路径
if(fp==NULL){
printf("\n打开文件失败。\n");
return 0;
}
//操作
//读 文件,fgetc,一个一个字符的读,*fp会自己加到下一个 ,【在关闭之前】
/*char ch=fgetc(fp);
printf("%c\n",ch);
ch=fgetc(fp);
printf("%c\n",ch);此代码只能读一个字符
*/
/*char ch; //一个一个字符的循环读取
while(EOF!=(ch=fgetc(fp)))
{
printf("%c",ch);
} */
//分行读,fgets:每次读一行,所以要建立字符数组 ,返回值是指针
/*char str[200];
fgets(str,200,fp);//注意str的位置 ,也会把fp给移到下一个位置
printf("%s",str);
fgets(str,200,fp);
printf("%s",str);
*/
//指定读:fread ,读到终端
/*char str[200];//={0};记得清零 ,不然直接赋值
int n=fread(str,1,20,fp);//fread:想读多少随意,返回值为实际读取的大小
str[n]='\0'; //fread把fp读给str,读20个1字节大小的内容
printf("%s",str);
*/
//读全部文件里面符合条件的
//如果要读完,就写while(fgets(str,200,fp))
/*char str[20]={0};
while(fread(str,1,20,fp))
{
printf("%s",str);
} */
//写文件
//写入 一个 字符:fputc,w是清空写
/*fputc('A',fp); */
//写字符串
/*char *str="D:\\计算机dev.c++\\c语言FILE\\FILE文件.exe" ;//如果要有换行效果,就写换行符就写‘\r\n’
fputs(str,fp);//不是fputc!! */
//随便写多少,fwrite
/*
//char *str="D:\\计算机dev.c++\\c语言FILE\\FILE文件.exehhh" ;
int num=12345;
fwrite(&num,1,sizeof(num),fp);
//文件指针定位fseek
fseek(fp,0,SEEK_SET);
int num0;
fread(&num0,sizeof(num0),1,fp);
printf("%d\n",num0);
*/
//写结构体,记得用typedef
/*
Person p1={"张三","男",20};//汉字占两个字节
fwrite(&p1,1,sizeof(p1),fp);//写完后偏移到下一个
*/
//文件定位1.fseek
/*char str[200]={0};
fseek(fp,5,SEEK_SET);//SEEK_SET表示从头 ,SEEK_END表示到文件末尾
fread(str,2,100,fp);
printf("%s\n$$$$$\n",str);
fseek(fp,5,SEEK_CUR);//CUR表示从当前位置 向后走,如果改成-5就是 向前走
fread(str,2,100,fp);
printf("%s\n$$$$$\n",str); */
//2.rewind(指针),让文件指针重置到开头
//3.ftell(指针)返回值是从开头到当前位置的偏移量 ,告诉当前位置
//读最后一行
fseek(fp,-1,SEEK_END);
char ch=0;
int len=0;
while(fread(&ch,1,1,fp))
{
if(ch=='\n')
break;
fseek(fp,-2,SEEK_CUR);
len++;//统计退了多少格
}
printf("$$$$$%d\n",len);
fseek(fp,-len,SEEK_END);
char *a=malloc(sizeof(char)*len+1);//释放后打2333
memset(a,0,len+1);//memset函数,清空动态申请的内存
fread(a,1,len,fp);
printf("$$$$$$%s\n",a);
free(a);//2333
//EOF :返回值,宏,不在文件中,表示读到末尾了
//关闭文件
fclose(fp);//打开了就要关
return 0;
}
借鉴:不死的韭菜