- 本篇会加入个人的所谓‘鱼式疯言’
- ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言,而是理解过并总结出来通俗易懂的大白话,我会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的,可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念
前言
💕💕💕艾迪巴帝,友子们,今天我们将推开 文件操作 的大门
主要讲的有:
- ⽂件的引入?
- ⼆进制⽂件和⽂本⽂件?
- ⽂件的打开和关闭
- ⽂件的顺序读写
💖💖💖
一.文件的引入
1.为什么要使用文件?
如果没有⽂件,我们写的程序的数据是存储在电脑的内存中
如果程序退出,内存回收,数据就丢失了,等再次运⾏程序,是看不到上次程序的数据的
如果要将数据进⾏持久化的保存,我们可以使⽤ ⽂件。
2. 什么是文件
磁盘上的⽂件是⽂件。
但是在程序设计中,我们⼀般谈的⽂件有两种:程序⽂件、数据⽂件(从⽂件功能的⻆度来分类的)
2.1 程序文件
程序⽂件包括源程序⽂件(后缀为 .c )
⽬标⽂件(windows环境后缀为 .obj)
可执⾏程序(windows环境后缀为 .exe)。
2.2 数据⽂件
⽂件的内容不⼀定是程序,⽽是程序运⾏时读写的数据,
⽐如程序运⾏需要从中读取数据的⽂件,或 者输出内容的⽂件。
本章讨论的是数据⽂件。
在以前各章所处理数据的输⼊输出都是以终端为对象的,即从终端的键盘输⼊数据,运⾏结果显⽰到 显⽰器上。
其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使⽤,这⾥处理的就是磁盘上⽂件.
2.3 文件名
⼀个⽂件要有⼀个唯⼀的⽂件标识,以便⽤⼾识别和引⽤。
⽂件名包含3部分:⽂件路径+⽂件名主⼲+⽂件后缀
例如: c:\code\test.txt
为了⽅便起⻅,⽂件标识 常被称为 ⽂件名
鱼式疯言
就是说呢😊😊😊
我们文件时在磁盘上的,用来存储数据的,文件可以放程序也可以放数据,我们可以在终端(下面第一张的小黑框框),也可以在我们下面磁盘上处理(下面第二张文件路径图)
(1).
(2).
3.二进制文件和文本文件
根据数据的组织形式,数据⽂件被称为⽂本⽂件 或者⼆进制⽂件。
数据在内存中以⼆进制的形式存储,如果不加转换的输出到外存,就是⼆进制⽂件。
如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的⽂件就是⽂本⽂件。
⼀个数据在内存中是怎么存储的呢?
字符⼀律以ASCII形式存储,数值型数据既可以⽤ASCII形式存储,也可以使⽤⼆进制形式存储。
如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占⽤5个字节(每个字符⼀个字节),⽽⼆进制形式输出,则在磁盘上只占4个字节
#include <stdio.h>
int main()
{
int a = 10000;
FILE * pf = fopen("test.txt", "wb");
fwrite(&a, 4, 1, pf);
//⼆进制的形式写到⽂件中
fclose(pf);
pf = NULL;
return 0;
}
文本文件是不打开的哦❤️❤️❤️
那该怎么办呢?
请宝子们看下面分解
4.文件打开和关闭
4.1流和标准流
<1> 流
我们程序的数据需要输出到各种外部设备
也需要从外部设备获取数据
不同的外部设备的输⼊输出 操作各不相同
为了⽅便程序员对各种设备进⾏⽅便的操作,我们抽象出了 流 的概念,我们可以把流 想象成流淌着字符的河。
C程序针对⽂件、画⾯、键盘等的数据输⼊输出操作都是通过流操作的。
⼀般情况下,我们要想向流⾥写数据,或者从流中读取数据,都是要打开 流,然后操作。
<2> 标准流
那为什么我们从键盘输⼊数据,向屏幕上输出数据,并没有打开流呢? 那是因为C语⾔程序在启动的时候,默认打开了3个流:
• stdin - 标准输⼊流,在⼤多数的环境中从键盘输⼊,scanf函数就是从标准输⼊流中读取数据。
• stdout - 标准输出流,⼤多数的环境中输出⾄显⽰器界⾯,printf函数就是将信息输出到标准输出 流中。
• stderr - 标准错误流,⼤多数环境中输出到显⽰器界⾯。
<3> 标准流的栗子🌰
#include<stdio.h>
int main()
{
char arr[10]="abcdefg\n";
fprintf(stdout,arr);
//用 fprintf 标准输出流输出
printf(arr);
//普通的 printf 输出
}
鱼式疯言
其实,在我们的运行程序时
我们的编译器就会在底层运行用到我们这三个标准流
输入,输出,错误。
小伙伴了解一下即可,不需要深入研究
这是默认打开了这三个流,我们使⽤scanf、printf等函数就可以直接进⾏输⼊输出操作的。
stdin、stdout、stderr 三个流的类型是:
FILE* ,通常称为⽂件指针。
C语⾔中,就是通过 FILE* 的⽂件指针来维护流的各种操作的。
鱼式疯言
啥是 流 呢?
说白了,就是一个中介,一个中转站,一个快递员,一个转换器,一个中枢枢纽…
上面我们提及了一个陌生的概念,文件指针
这是什么呢?
不妨小伙伴都和我一起继续往下找找答案吧😊😊😊
4.2 文件指针
缓冲⽂件系统中,关键的概念是“⽂件类型指针”,简称“⽂件指针”。 每个被使⽤的⽂件都在内存中开辟了⼀个相应的⽂件信息区,⽤来存放⽂件的相关信息(如⽂件的名 字,⽂件状态及⽂件当前的位置等)。
这些信息是保存在⼀个结构体变量中的。该结构体类型是由系 统声明的,取名FILE
例如,VS2013编译环境提供的 stdio.h 头⽂件中有以下的⽂件类型申明:
struct _iobuf
{
char* _ptr;
int _cnt;
char* _base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char* _tmpfname;
};
typedef struct _iobuf FILE;
不同的C编译器的FILE类型包含的内容不完全相同,但是⼤同⼩异。 每当打开⼀个⽂件的时候,系统会根据⽂件的情况⾃动创建⼀个FILE结构的变量,并填充其中的信 息,使⽤者不必关⼼细节。 ⼀般都是通过⼀个FILE的指针来维护这个FILE结构的变量,这样使⽤起来更加⽅便。 下⾯我们可以创建⼀个FILE*的指针变量:
FILE* pf;
//⽂件指针变量
这上面的概念友友们小小过过眼,知道这个概念就欧克啦
咱们主要的是知道并掌握文件指针的使用 ! ! !
定义pf是⼀个指向FILE类型数据的指针变量。
可以使pf指向某个⽂件的⽂件信息区(是⼀个结构体变 量)。
通过该⽂件信息区中的信息就能够访问该⽂件。
鱼式疯言
通过⽂件指针变量能够间接找到与它关联的⽂件.
接下来,该我们实操起来啦💕💕💕
4.3 文件的打开和关闭
⽂件在读写之前应该先打开⽂件,在使⽤结束之后应该关闭⽂件。
在编写程序的时候,在打开⽂件的同时,都会返回⼀个 FILE* 的指针变量指向该⽂件,也相当于建⽴了 指针和⽂件的关系。
ANSIC 规定使⽤ fopen 函数来打开⽂件, fclose 来关闭⽂件。
//打开⽂件
FILE * fopen ( const char * filename, const char * mode );
//关闭⽂件
int fclose ( FILE * stream );
mode 表⽰⽂件的打开模式,下⾯都是⽂件的打开模式:
友子们是不是都不想看了,我也是😭😭😭
太多了吧,不过我们只需要会前面的 **“r”**和 **“w”**就足够啦!
4.3.1 “w” 的栗子说明
/* fopen fclose example */
#include <stdio.h>
int main()
{
FILE* pFile;
//打开⽂件
pFile = fopen("myfile.txt", "w");
//⽂件操作
if (pFile != NULL)
{
fputs("fopen example", pFile);
//关闭⽂件
fclose(pFile);
}
return 0;
}
鱼式疯言:
有该文件我们可以用 “w” 自行打开,
如果没有该文件的话,我们就可以通过 “w” 自动创建
具体对文件的流程就是
打开文件——>文件操作——>关闭文件.
4.3.2 “r” 的栗子说明
就像上面这样要是没有该文件的情况,
如果我们用 “r” 来实践呢!!!
/* fopen fclose example */
#include <stdio.h>
int main()
{
FILE* pFile;
//打开⽂件
pFile = fopen("myfile.txt", "r");
//⽂件操作
if (pFile == NULL)
{
perror("fopen");
return 1;
}
//关闭⽂件
fclose(pFile);
return 0;
}
小伙伴都看清楚区别了吧 “w” 和 “r”的区别吧😁😁😁
鱼式疯言
我是这样理解的
w—> write 是写的意思吧,如果我们要写,当我们该文件名时,是不是可以先创个文件再写呢 ! ! !
r——> read 是读的意思呢,如果我们要读,那如果也没有该文件名呢,连个文件都没有肯定会报错呢! ! !
如果都有该文件名,这样我们就可以用下面的顺序读写函数对文件进行操作了。💖💖💖
5.文件的顺序读写
5.1 顺序读写函数介绍
蛙趣,好多啊😣😣😣
没关系,下面由小编来带着大家一起学
咱们两两搭配起来用哦💖💖💖
5.2 fgetc 与 fputc
/*fputc与fgetc_test*/
#include<stdio.h>
int main()
{
FILE* putpile = fopen("gt.txt", "w");
if (putpile == NULL)
{
perror("fopen->putpile");
return 1;
}
for (int i = 0; i < 26; i++)
{
fputc('a' + i, putpile);
}
fclose(putpile);
putpile = NULL;
//这里一定要要指针置为空
//否则就有可能出差错
FILE* getpile = fopen("gt.txt", "r");
if (getpile == NULL)
{
perror("fopen->getpile");
return 1;
}
int ch = fgetc(getpile);
printf("%c\n", ch);
ch = fgetc(getpile);
printf("%c\n", ch);
ch = fgetc(getpile);
printf("%c\n", ch);
ch = fgetc(getpile);
printf("%c\n", ch);
//for (int i = 0; i < 4; i++)
//{
// printf("%c\n", fgetc(getpile));
//}
//也可用循环打印
fclose(getpile);
getpile = NULL;
//最后要关闭文件指针哦
return 0;
}
根据上面的代码,我们就可以对文本进行 写 与 读 啦 !!!
5.3 fgets 与 fputs
<1>.举个栗子
#include<stdio.h>
int main()
{
FILE* putpile = fopen("gt.txt", "w");
if (putpile==NULL)
{
perror("fopen");
return 1;
}
fputs("abcde", putpile);
fclose(putpile);
putpile = NULL;
FILE* getpile = fopen("gt.txt", "r");
if (getpile==NULL)
{
perror(fopen);
return 1;
}
char arr[5];
fgets(arr,4, getpile);
printf(arr);
fclose(getpile);
getpile = NULL;
return 0;
}
鱼式疯言
唯一要注意一点是:
num : 这里是要指定输出字符串大小的
5.3. fprintf 与 fscanf
<1>.举个栗子
struct Stu
{
char name[20];
int age;
float score;
};
#include<stdio.h>
//fprintf与fscanf_test
int main()
{
struct Stu s1 = { "hehehhhh" ,112, 12.366 };
struct Stu s2 = {0};
FILE* pc = fopen("gt.txt", "w");
if (pc==NULL)
{
perror("fopen");
return 1;
}
fprintf(pc, "%s %d %.1f", s1.name, s1.age, s1.score);
//fprintf 可以用于写文件
fclose(pc);
pc = NULL;
FILE* pf = fopen("gt.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写读文件
//
fscanf(pf, "%s %d %f", s1.name, &(s1.age), &(s1.score));
//写出该文件的内容拷贝在结构体 s 上
fprintf(stdout, "%s %d %.1f\n", s1.name, s1.age, s1.score);
//读取或输出该结构体
printf("%s %d %.1f\n", s1.name, s1.age, s1.score);
fclose(pf);
pf = NULL;
return 0;
}
w方式时,我们用 fprintf 可以写入
r方式时,我们可以通过 fscanf 从文本中传出数据到结构体
再通过标准输出流 stdout 打印我们的或者 printf 直接输出
5.4. fwrite 和 fread
<1>. fwrite 的栗子
//fwrite
#include<stdio.h>
struct Stu
{
char name[20];
int age;
float score;
};
int main()
{
struct Stu s = {"zhangsan", 20, 90.5};
FILE* pf = fopen("data.txt", "wb");
if (pf == NULL)
{
return 1;
}
//二进制的形式写文件
fwrite(&s, sizeof(s), 1, pf);
fclose(pf);
pf = NULL;
return 0;
}
前面我们看到fprintf写进去的文本,
下面小伙伴来看看这两者的区别
<2>. fread 的栗子
#include<stdio.h>
//fread_test
struct Stu
{
char name[20];
int age;
float score;
};
int main()
{
struct Stu s = { 0 };
FILE* pf = fopen("data.txt", "rb");
if (pf == NULL)
{
return 1;
}
//二进制的形式读文件
fread(&s, sizeof(s), 1, pf);
printf("%s %d %.1f\n", s.name, s.age, s.score);
fclose(pf);
pf = NULL;
return 0;
}
上面我们讲到了二进制文件在文本文件中是会变乱的
但我们的读取还是一样的读取
鱼式疯言
这点充分说明了,文件的种类虽然不同,形式发生了改变 ,但是文件的内容一般不会改变.
以上顺序读写函数的操作,啥叫 顺序读写 呢🤔🤔🤔
显而易见 顺序 顺序 就是当相当于我们C语言程序自上而下的顺序执行一样,后期我们会进一步讲解我们的文件随机读写,文件读取的判定和文件缓冲区的讲解…
友友们敬请期待哦 !!!
总结
🤞🤞🤞在本篇文章中,我们主要讲解有
- ⽂件的引入的概念,类别!
- ⼆进制⽂件和⽂本⽂件的认识
- .文件指针的理解,以及利用函数对⽂件的打开和关闭
- ⽂件的顺序读写,不同文件操作函数的理解以及实际操作文本文件和二进制文件。
💖💖💖本次博文就到这里了,感觉各位小伙伴的赏脸品读小编写的拙作哦,
如果觉得小编写的还不错的咱可支持三关下,不妥当的咱评论区指正
希望我的文章能给各位家人们带来哪怕一点点的收获就是小编创作的最大动力💖💖💖