前言
我们接着文件操作(上)的内容,继续给大家讲解文件操作。
在本文中,我们将要学习文件如何在程序中作用的原理以及一些简单的文件打开或关闭的操作。
那么,废话不多说,就让我们开启学习之旅吧!!!👌👌👌💕
1. 文件的打开和关闭
在讲解文件的操作之前,我们还得先认识一个概念——“流”
1.1 流
联想到我在上文提到过的用来保存数据的外部设备——“磁盘”。事实上也有很多其它的外部设备也可以存储数据或者进行数据的交互,比如:光盘、软盘、硬盘、屏幕、键盘等等。每一个外部设备的操作方式都不一样,难道要我们程序员都逐一记住并进行操作吗?我们程序员是虽然是一个神圣的职业,但也经不起这样造啊!程序员也是人啊!
为此,程序员就抽象出一个“流”的概念。我们可以把它想象成一个流淌着数据的河流,在河的不远处有一个个闸门,而这些闸门分别代表着每一个不同的外部设备,但是这个闸门不需要我们程序员自己打开,而是闸门在程序运行时我们使用根据编译器给我们提供函数就会自行打开对应的闸门了。对此,程序员大可不必关心如何将数据传递给外部设备的问题了,它们只需要知道如何使用这些工具即可。这个做法方便程序员对各种设备进行操作。
C语言针对文件、画面、键盘等的数据输入输出操作都是通过流操作完成的。
一般情况下,我们想要向流里写入数据,或者从流里输入数据,都是要打开流,然后再操作。
1.2 标准流
讲完流的概念了,我们再来讲讲标准流。
我在上面提到过C语言针对文件、画面、键盘等的数据输入输出操作都是通过流操作完成的。可是我们在键盘上输入数据到程序中或者在屏幕上显示数据,好像并没有在代码中写所谓的打开流的操作啊!
这个就是标准流的魅力了。C语言程序在启动时,默认打开三个标准流:
- stdin : 标准输入流。在大多数环境中从键盘输入数据,scanf函数就是从标准输入流里读取数据。
- stdout : 标准输出流。在大多数环境中从显示器上输出数据,printf就是将信息输出到标准输出流中。
- stderr : 标准错误流。大多数环境中输出到显示器界面。
这是默认打开的三个流,我们直接使用scanf和printf函数就可以直接进行输入和输出信息的操作了。
stdin、stdout、stderr三个流的类型是:FILE*
,通常被称为文件指针。
C语言中就是通过文件指针来维护流的各种操作。
2. 文件指针
学的深入的读者可能会提出一个这样的问题,文件是以何种形式在内存中存储的?
每个被使用的文件都会在内存中开辟一个相应的文件信息区,用来存放文件的相关信息(如文件名、文件状态以及文件当前的位置等)。这些信息是保存在一个名为FILE的结构体变量中。至于为什么是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* pf;//文件指针变量
定义pf是一个指向名为FILE类型数据的指针变量。可以使pf指向某个文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问文件。也就是说,通过文件指针变量我们就能够间接找到与它相关联的文件。
3. 文件的打开和关闭
文件在进行操作(读/写)之前,应该先打开文件,在使用结束后关闭文件。
在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也就相当于建立了文件和指针的联系了。
ANSI C规定使用fopen函数来打开文件,fclose来关闭文件。
两个函数的原型:
fopen的返回值:
在fopen函数中,有一个形参const char* mode
。这个mode表示文件的打开方式,在下面我将一一列举出文件打开的各种形式:
文件打开方式 | 含义 | 如果指定的文件不存在 |
---|---|---|
“r” (只读) | 只为了从文件输出数据,打开一个已经存在的文本文件 | 出错 |
“w”(只写) | 只为了输入数据到文件,打开一个文本文件 | 创建一个新的文件 |
“a” (追加) | 向文本文件末尾添加数据 | 创建一个新的文件 |
“rb” (只读) | 为了从文件输出数据,打开一个已经存在的二进制文件 | 出错 |
“wb”(只写) | 为了输入数据到文件,打开一个二进制文件 | 创建一个新的文件 |
“ab”(追加) | 向文本文件末尾添加数据 | 创建一个新的文件 |
“r+”(读写) | 为了读和写,打开一个文本文件 | 出错 |
“w+”(读写) | 为了读和写,建立一个新的文本文件 | 创建一个新的文件 |
“a+” (读写) | 打开一个文本文件,在文本文件的末尾进行读写 | 创建一个新的文件 |
“rb+”(读写) | 为了读和写,打开一个二进制文件 | 出错 |
“wb+”(读写) | 为了读和写,建立一个新的二进制文件 | 创建一个新的文件 |
“ab+”(读写) | 打开一个文本文件,在二进制文件的末尾进行读写 | 创建一个新的文件 |
实例代码:
#include<stdio.h>
int main()
{
//创建一个文件指针变量pf
FILE* pf;
//打开文件(打开流)
pf = fopen("test.txt","w");
//文件写操作
if(pf != NULL)//这里if的目的是:文件打开的时候可能失败,如果失败的话,返回空指针
{
fputs("好好学习,天天向上",pf);
//关闭文件
fclose(pf);
pf = NULL;//防止pf变为野指针
}
return 0;
}
总结
对此,文件操作(中)就讲完了。本文主要讲解了,文件操作是如何操作的,以及操作的一些基础细节。我们还讲了流的概念。