C语言:文件操作
文件的概念
文件是计算机用于存储数据的工具,我们计算机磁盘上的数据是混乱的,但是我们计算机系统通过文件的方式记录数据在磁盘上的位置来将数据整齐划分。
文件的类型
文件有两种类型,数据文件与程序文件
程序文件是用来执行的文件,就比如我们写的代码,存储代码数据的文件被称为程序文件
数据文件可以是很多,比如txt什么之类的
一般程序文件会读取数据文件的数据,并处理读取过的数据,将结果再传输到数据文件当中
关系图
text.exe从数据文件中获取数据后处理并将处理结果输入到数据文件中
流
程序在运行时需要从外部设备获取数据或向外部设备输出数据,不同设备的操作方式不同,为了方便管理这种操作方式,我们抽象出了一种流的概念
程序只需向流中提取和输入数据,操作系统就能为完成程序与外部设备的数据交互。
标准流
stdout--标准输出流,在大多数情况下将数据输出到屏幕上
stdin --标准输入流,在大多数情况下从键盘中获取数据
stderr --标准错误流,大多数情况下奖错误信息输出到屏幕上
程序是默认打开这三个流的,所以当我们使用scanf和printf时,不需要指明流,自然就可以输入输出。
文件指针
当我们打开一个文件时,系统会给我们创建一个结构体,这个结构体包含了这个文件许多相关信息(文件名,文件状态,文件位置等),这个结构体的名称为FILE,
当我们打开一个文件时,大部分情况下会返回一个文件指针,程序可以通过这个文件指针来控制这个文件
这里的pf1其实就是我们所说的流,所谓的流其实就是一个文件指针,我们的屏幕显示也是一个指针,当我们向这个屏幕当中写入内容时其实就是向某个文件当中写入内容,当我们想要从键盘中获取数据时,其实也是从键盘文件中获取数据
文件的操作
fopen
想要了解文件的操作,那么我们就必须先了解fopen,当我们想要对文件数据进行操作时,我们首先要做的是先要打开文件,fopen函数可以打开文件,并且返回文件流,让我们可以对文件进行操控
FILE *fopen(const char *filename, const char *mode);
其中filename是对应文件的绝对路径,mode是文件的打开方式,它们都是const char*类型,所以我们传递数据时,我们需要传递字符串。
它的返回值是FILE*,我们后续可以通过这个返回值来对这个文件进行操作
我们都知道文件的绝对路径是什么,那么说明是文件的打开方式呢
模式 | 方式 | 含义 | 如果指定文件不存在 |
"r" | 只读 | 为了读取数据,打开一个存在的文本文件 | 出错 |
"w" | 只写 | 为了输入数据,打开一个文本文件,存在则清空数据。 | 创建一个新的文件 |
"a" | 追加 | 向文本文件末尾添加数据,没有则创建一个 | 创建一个新的文件 |
"rb" | 只读 | 为了输⼊数据,打开⼀个⼆进制⽂件 | 出错 |
"wb" | 只写 | 为了输出数据,打开⼀个⼆进制⽂件,如果存在同名文件,则清空原先数据 | 创建一个新的文件 |
"ab" | 追加 | 向⼀个⼆进制⽂件尾添加数据 | 创建一个新的文件 |
"r+" | 读写 | 为了读和写,打开⼀个⽂本⽂件 | 出错 |
"w+" | 读写 | 为了读和写,建议⼀个新的⽂件,如果存在同名文件,则清空原先数据 | 创建一个新的文件 |
"a+" | 读写 | 打开⼀个⽂件,在⽂件尾进⾏读写 | 创建一个新的文件 |
"rb+" | 读写 | 为了读和写打开⼀个⼆进制⽂件 | 出错 |
"wb+" | 读写 | 为了读和写,新建⼀个新的⼆进制⽂件 | 创建一个新的文件 |
"ab+" | 读写 | 打开⼀个⼆进制⽂件,在⽂件尾进⾏读和写,如果存在同名文件,则清空原先数据 | 创建一个新的文件 |
以"w"形式打开
FILE* fp = fopen("text1.txt", "w");
如果文件不存在则报错,如果文件存在返回这个文件的流
通过这个流我们可以在文件中写入数据,后面我们会学习如何
以"r"形式打开
FILE* fp = fopen("text1.txt", "r");
当我们传递路径时也可以使用绝对路径传递
FILE* fp = fopen("My_Code\gua-gua\Project47\Project47\text1.txt", "a");
fclose
fclose使用来关闭文件的函数,fclose格式如下图所示
int fclose(FILE *stream);
当我们不需要一个流时,我们需要规范操作,这个流关闭,否则会引发一系列问题
文件读写
文件读写分为顺序读写和随机读写
顺序读写
fputc
int fputc(int char,FILE* stream)
char:int以int类型传递字符参数,实际使用的是int的低8位
stream:目标文件指针(可以是stdout,stdin,stderr)
成功:成功返回字符ASCII对应的int
失败:返回EOF(-1),并设置errno
用法示例:
我们向stdout文件中传递字符更直观观察fputc功能
#include<stdio.h>
int main()
{char CH[15] = "ABCDEFGHIJKL";for (int i = 0; i < sizeof(CH); i++){fputc(CH[i], stdout);}
}
程序结果:
我们向系统默认打开的文件stdout中输入CH的数据,显示结果如上
fgetc
函数原型
int fgetc(FILE *stream);
从文件第一个位置开始获取字符,获取一次,文件光标向后移动一位,当文件光标移动到文件末尾,函数返回EOF(-1)
我们来演示一下
目标文件内容
ABCDEF12DSADSD
演示代码如下
#include<stdio.h>
int main()
{FILE* fp=fopen("text.txt", "r");char CH = fgetc(fp);while (CH!=EOF){printf("%c ", CH);CH = fgetc(fp);}
}
运行结果
每次读取文件的一个字符,光标都会向后移动一格
fgets
char *fgets(char *str, int n, FILE *stream);
str:目标字符串
n:获取字符串个数(包含结尾字符串'\0')
stream:流
代码演示
#include<stdio.h>
int main()
{FILE* fp=fopen("text.txt", "r");char CH[255];fgets(CH,sizeof(CH),fp);printf("%s", CH);fgets(CH, sizeof(CH), fp);printf("%s", CH);
}
文件内容
ABCDEF12DSADSD
dasdasfasfadfdas
输出结果
fputs
函数原型
int fputs(const char *str, FILE *stream);
str:待输出字符串
stream:目标文件流
成功:返回非负整数,通常是输出字符数
返回:返回EOF(-1)
代码演示
#include<stdio.h>
int main()
{FILE* fp=fopen("text.txt", "r");char CH[255]="HELLO,WORLD";fputs(CH, stdout);
}
输出结果
向标准输入文件stdout输入数据
fprintf
函数原型为
int fprintf(FILE *stream, const char *format, ...);
用于向文件流中进行格式化输出
参数:
stream:指定对应的文件流
format:指定输出格式
...:可变参数
演示代码
#include<stdio.h>
int main()
{FILE* fp=fopen("text.txt", "w");fprintf(fp, "%s %d %s", "hello", 100, "world!");
}
程序结果
文档内容
hello 100 world!
fscanf
函数原型
int fscanf(FILE *stream, const char *format, ...);
用于从文件中读取格式化输入
stream:输入流文件指针
format:读取格式
...:可变参数
成功:返回成功匹配和赋值的输入项
失败:返回EOF(-1)
代码演示
#include<stdio.h>
int main()
{FILE* fp=fopen("text.txt", "r");char ch1[256];int num=0;char ch2[256];fscanf(fp, "%s%d%s", ch1,&num,ch2);printf("ch1:%s num:%d ch2:%s", ch1, num, ch2);
}
文档内容
hello 100 world!
演示结果