前言
当我们想把内容记录下来,选择删除数据的时候,数据才会不存在,这是关于数据持久化的问题,一般数据持久化的方法有:把数据存放在磁盘文件、存放在数据库等。
使用文件我们可以将文件直接存放在电脑硬盘上,做到了数据的持久化,下面就让小羊带大家学习文件操作~~
一、什么是文件
磁盘上的文件是文件;
程序设计中,从文件的功能来分,文件分为数据文件和程序文件;
1.1 程序文件
- 源程序文件(后缀为.c)
- 目标文件(windows环境后缀为.obj)
- 可执行程序(windows环境后缀为.exe)
1.2 数据文件
文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件或者输出内容的文件。(这篇文章学习的是数据文件)
在以往我们处理数据的输入输出都是以终端为对象,就是从终端的键盘输入数据,运行结果显示到显示器上。但我们有时候会把信息输出到磁盘上,有需要的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上的文件。
1.3 文件名
一个文件要有一个唯一的文件标识,以便用户识别和引用
文件名包括三部分:文件路径+文件名主干+文件后缀
例如:C:\code\test.txt
为了方便起见,文件标识被称为文件名
二、文件的打开和关闭
2.1 文件指针
缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是由系统声明的,取名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指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。(返回的是FILE*的指针变量,指向文件信息区的起始地址)
2.2 文件的打开和关闭
文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。
在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。
打开文件:
FILE * fopen ( const char * filename, const char * mode );
参数:
filename:包含要打开的文件的名称的 C 字符串。其值应遵循运行环境的文件名规范,并且可以包含路径。
mode:包含文件访问的模式。
返回值:如果文件成功打开,该函数将返回指向FILE对象的指针。
文件使用方式 | 含义 | 如果指定文件不存在 |
“r”(只读) | 为了输入数据,打开存在的文本文件 | 出错 |
“w”(只写) | 为了输出数据,打开一个文本文件 | 建立一个新的文件 |
“a”(追加) | 向文本文件尾添加数据 | 建立一个新的文件 |
“rb”(只读) | 为了输入数据,打开一个二进制文件 | 出错 |
“wb” (只写) | 为了输出数据,打开一个二进制文件 | 建立一个新的文件 |
“ab” (追加) | 向一个二进制文件尾添加数据 | 建立一个新的文件 |
“r+”(读写) | 为了读和写,打开一个文本文件 | 出错 |
“w+” (读写) | 为了读和写,建议一个新的文件 | 建立一个新的文件 |
“a+” (读写) | 打开一个文件,在文件尾进行读写 | 建立一个新的文件 |
“rb+” (读写) | 为了读和写打开一个二进制文件 | 出错 |
“wb+” (读写) | 为了读和写,新建一个新的二进制文件 | 建立一个新的文件 |
“ab+” (读写) | 打开一个二进制文件,在文件尾进行读和写 | 建立一个新的文件 |
注意:
输入的模式要用双引号引起来,这样就表示字符串,传过去的就是地址
关闭文件:
int fclose ( FILE * stream );
参数:
指向指定要关闭的流的FILE对象的指针。
返回值:
如果流成功关闭,则返回零值。失败时,将返回EOF。
#include<stdio.h> #include<string.h> int main() { //打开文件,读文件 FILE* pf = fopen("date.txt", "r");//默认的路径是test.c的路径 //"r"注意是双引号 if (p == NULL); { perror("fopen"); return 1; } //关闭文件 fclose(p); p = NULL;//这个指针变量不再使用的时候,置为空指针 return 0; }
三、文件的顺序读写
3.1 顺序读写函数介绍
功能 | 函数名 | 适用于 |
字符输入函数 | fgetc | 所有输入流 |
字符输出函数 | fputc | 所有输出流 |
文本行输入函数 | fgets | 所有输入流 |
文本行输出函数 | fputs | 所有输出流 |
格式化输入函数 | fscanf | 所有输入流 |
格式化输出函数 | fprintf | 所有输出流 |
二进制输入 | fread | 文件 |
二进制输出 | fwrite | 文件 |
C语言程序,只要运行起来,默认打开三个流:
- 标准输入流:stdin FILE*
- 标准输出流:stdout FILE*
- 标准错误流:stderr FILE*
要对文件操作时,只要产生一个与文件相关的流就可以。
读写数据时,我们把数据写入流中,读数据时从流中读
3.2 读写函数的使用
1. fputc(将字符写入流)
int fputc ( int character, FILE * stream );
参数:
character:要输入的字符。
stream:指向标识输出流的FILE对象的指针。
fputc函数的应用:
#include<stdio.h> int main() { FILE* pf = fopen("date.txt", "w"); if (pf == NULL) { perror("fopen"); return 1; } fputc('a', pf); fputc('b', pf); fputc('c', pf); fclose(pf); pf = NULL; return 0; }
#include<stdio.h> int main() { FILE* pf = fopen("date.txt", "w"); if (pf == NULL) { perror("fopen"); return 1; } char ch = 0; for (ch = 'a'; ch <= 'z'; ch++) { fputc(ch, pf); } fclose(pf); pf = NULL; return 0; }
内容在文件中显示出来就得打开文件关闭文件,为什么屏幕就不用呢?
因为在C语言中,程序运行起来,就会打开三个流:stdio—标准输入流,stdout—标准输出流(在屏幕中显示),stderr—标准错误流(这三个都是FILE*类型的)
如果想要上个代码打印在屏幕上,我们只要将p改为stdout。
2. fgetc(从流中获取字符)
int fgetc(FILE* stream);
**返回值:**成功后,将返回字符读取(提升为 int 值)。
返回类型为 int 以适应特殊值EOF
如果位置指示器位于文件末尾,则该函数返回EOF
从文件中读:
#include<stdio.h> int main() { FILE* pf = fopen("date.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } int ch = 0; while ((ch = fgetc(pf) )!= EOF) { printf("%c ", ch); } fclose(pf); pf = NULL; return 0; }
从键盘上读:
#include<stdio.h> int main() { int ch = fgetc(stdin); printf("%c\n", ch); ch = fgetc(stdin); printf("%c\n", ch); ch = fgetc(stdin); printf("%c\n", ch); ch = fgetc(stdin); printf("%c\n", ch); return 0; }
传文件指针,从文件中读;传stdin,从键盘上读
3. fputs(将字符串写入流)
int fputs(const char* str,FILE* stream);
参数:
str:包含要写入流的内容的 C字符串。
stream:指向标识输出流的 FILE 对象的指针。(stdin可以用作从标准输入读取的参数)
fputs函数的应用:
#include<stdio.h> int main() { FILE* pf = fopen("date.txt", "w"); if (pf == NULL) { perror("fopen"); return 1; } fputs("hello\n", pf); fputs("goodby\n", pf); fclose(pf); pf = NULL; return 0; }
注意:
fputs 与 puts 的不同之处不仅在于可以指定目标流,而且 fputs 不会写入其他字符,而puts会自动在末尾附加换行符。
『C语言进阶』文件操作(二):https://developer.aliyun.com/article/1392712