前言:提到文件我们能先想到什么呢,可能大家想到的就是那一个个磁盘中存储的东西,没错,磁盘中储存的就是文件。文件分为:①程序文件( 源程序文件 – 后缀名:.c,目标文件 – 后缀名:.obj , 可执行程序 – 后缀名:.exe) ②数据文件(文件内容不一定是程序,而是程序输入/输出时所要读取/存储的数据) ,本篇文章讨论的时数据文件。
目录
一、文件名
不知道大家有没有想过,姓名在我们生活中占了多大的作用,如果我们没有姓名的话,我们不禁会在心里产生这样一个疑问:
因此,为了避免这种情况,我们有了姓名,而文件也是如此,每个文件都有一个唯一的标识,这个标识我们通常称为文件名。
文件名:文件路径 + 文件名主干 + 文件后缀
例:c:\pick\test.txt (由于转义字符,我们在VS中书写如下:c:\pick\test.txt )
二、文件的打开与关闭
平时我们打开文件用鼠标双击就打开了,但是我们在写代码时可不能这样打开哦,要写一个指令去①打开相关的文件。
说到打开,那就会产生另一个问题 -- ②以何种方式打开?这就像我们去别人家一样,我们可以打开房门在门外向房间里看一看,也可以走进去使用或者拿走家中的一些东西,当然,进去也有不同的方式(包括不限于强行闯入)。
好了,我们先回到问题①,我们要使用文件,就必须先打开文件,因此,函数 fopen 就出现了。现在,我们可以讨论问题②了,我在这里列举了所有的打开方式,以及对应的操作,如下图:
看似很多,其实我们可以很容易的总结。基础操作方式分为三个:r -- 读,w -- 写,a -- 追加,再此基础上加 b --- 二进制文件进行操作,加 + --- 进行读写,值得注意的是,不同的打开方式面对指定的文件不存在时产生的后果也不同:若有基础操作 r --- 报错,若有基础操作 b 和 a --- 新建一个空白文件。
看到这里,大家可能也直到 fopen 的用法了,FILE* fopen( 文件标识 , 打开方式) , 可以看到这个函数返回的是一个指针,指向的是 FILE 类型的数据,也就是文件。例:FILE* p = fopen(...)
三、文件的读写
既然文件我们可以以不同的方式打开了,那么我们现在就可以对文件与内存进行操作了。
1.文件的顺序读写:
顺序读写,顾名思义,就是在文件指针默认的位置进行操作,我在这里列举了一些操作函数, 如下图:
需要注意的是:fgetc函数在读取1个数据后文件指针会向后移动一个单位。
补充:int sscanf(char* str , 格式....) -- 将参数按照指定格式输入到str字符串中。
int sprintf(char* str , 格式...) -- 将字符串按照指定格式输出到参数中。
2.文件的随机读写:
有顺序就会有随机。 ---- 鲁迅
如果想要实现文件的随机读写,那么我们必须要控制文件的指针,这里就不得不提到 fseek 函数了。
int fseek (FILE* p ,int size_t num,int origin) -- 流中从origin位置偏移num个字节。
*那么新的问题来了,这个origin位置要怎么确定呢?这里也列举了3个不同的位置:
SEEK_SET 文件开头
SEEK_CUR 指针的当前位置
SEEK_END 文件结尾
有了这些,怕是指针飞的天花乱坠也能给找回来!
3.ftell 与 rewind
既然我们知道如何操纵文件指针了,那么就延伸出了一点知识:
①ftell : long int ftell( FILE* p) --- 返回当前指针位置距文件开头的偏移量
②rewind:void rewind( FILE* p) --- 将文件指针直接移动到文件开头位置(你皮任你皮,一键到开头)
四、文件的种类
文件可以划分为两种:①文本文件②二进制文件
我们都知道数据在内存中是以二进制的方式存储的,如果输出到文件的过程中不转换的话,那么 就会以二进制的形式输出到文件中,文件自然就是二进制文件,而如果转换成ASCll字符进行存储 的话,那文件就是文本文件 。
我们也可以自己做个测试,如下图:
①以二进制的方式输出 1000 到文件 test10.31.txt 中
②打开对应的文件,这时我们可以清楚的看得到,这玩意我们不认识,因为里面存放的是二进制,我们又没有以二进制的方式打开,所以我们看不懂。
③我们按照如下步骤去以二进制的方式打开文件:
首先,右击源文件 -> 找到现有项 -> 双击对应的文件打开。
打开后,我们右击该文件,单击打开方式,选择二进制方式打开,这样我们就看到了实际存储的数值,只不过这里是转换成十六进制了,我们稍加转换即可,由于是小端存储,因此实际存放的值是00 00 03 E8(地址从左到右逐渐减少),转换成十进制就是1000。
五、判定读取文件结束
1.feof 的错误理解:有很多人把 feof 作为判断判定文件否读取结束的函数,其实这是错误的, feof 的作用是用于在读取文件结束时判断是什么原因都区结束的。
2.判断文件是否读取结束的函数:
① 文本文件:
fgetc 、fgets
fgetc:当fgetc返回的值为 EOF 时,文件读取结束。
fgets:当fgets返回的值为 NULL 时,文件读取结束。
②二进制文件:
判断二进制文件是否读取结束时,要看其返回值,返回值小于读取的个数就说明读取结束。
当判断文件是否读取结束后就可以使用 feof 对读取结束的原因进行判定了。
feof:int feof(FILE* p ),若 feof 返回的值为非0,那么就说明当前光标后已经没有数值了。
例子如下:
int main()
{
//打开一个文件
FILE* p = fopen("F:\\en\\test.txt","r");
//判断是否打开
if(p == NULL)
{
perror("fopen:");
return;
}
int c = 0;
while(c = fgetc(p) != EOF)
{
//输出文本中的字符
putchar(c);
}
//读取结束、进行判断
//判断结束是否是因为读取错误
if(ferror(p)) //若文件读取产生错误,返回值为真
printf("I/O error when reading\n ");
//判断读取结束是否是因为读取到文件末尾
else if(feof(p))
printf("end of file reached successfully\n")
return 0;
}
六、文件缓冲区
我们不管是从内存进行输入还是输出,这些数据并不是同步进行的,而是先要将数据存放到 输入/输出缓冲区 ,待缓冲区存满之后才会将数据进行 输入/输出 。此外,对缓冲区进行 fflush (刷新) or 遇到‘\n’(换行) 时也会将数据进行 输入/输出 。fclose文件也会对缓冲区进行刷新。
代码奉上:
int main()
{
FILE* p = fopen("F:\\en\\test.txt", "w");
char arr[35] = "No way is impossbile to courage";
if (p == NULL)
{
perror("fopen:");
return;
}
//将字符串输出到文件中
fputs(arr, p);
//此时可打开文件,发现并没有数据写入
//等待10秒
printf("等待10秒\n");
Sleep(10000);
//刷新文件
fflush(p);
//再次等待10秒
printf("文件以写入,再次等待10秒\n");
Sleep(10000);
//打开文件,看到数据写入
//关闭文件
fclose(p);
p = NULL;
return 0;
}
以上,就是对文件操作的相关内容,有收获的朋友给个赞吧,创作不易(哭死)