★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
本文章介绍c语言的文件操作,包括复制文件,读取文件。早期的单机游戏中的数据有一些是存在配置文件里的,通过配置文件可以修改游戏里的数据。
举个例子,我改过的: 孤胆枪手-重装上阵 的配置文件。
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
目录
1.文件概念
★★★文件的分类★★★
数据文件,程序文件
★★★文件名★★★
文件路径+文件名+文件后缀
比如C:\Users\luotianyi\Desktop\data.exe
2.二进制文件与文本文件
★★★以二进制的000000111010100001111010直接存到文件中,是二进制文件。★★★
★★★以二进制的ASSIC存到文件中,是文本文件。文本文件是经过编码的,我们通常打开的txt文件是文本文件,文本编辑器是读不懂二进制信息的。★★★
通常ASSIC有128个字符,后来增加到了256个。也就是一个char的大小。但在现在的windows中,增加了中文编码。记事本下面的UTF-8就包含中文编码,使得1个char已经存不下更多的字符了,所以UTF-8有更多的编码方式,用更大的2个字节或者3个字节来存储1个字符,包含了中文以及其他国家的字符的编码。
通俗一点说,你的储存介质里的一个字节里存了00101011,文本编辑器并不认识00101011是什么,就像没学过计算机的人也不知道00101011是什么一样。而你想知道00101011是什么,就必须查ASSIC码表,同理,文本编译器底层是有二进制信息对应的ASSIC码表和其他符号的表的。给00101011起个名字叫‘+’,以后我们输入或者读取‘+’,文本编译器经过底层的对应关系,就能在内存中找到这一段二进制信息。
所以说,★★★文本编辑器不认识二进制信息,但认识经过编码后的二进制信息。★★★
3.流的概念
流相当于一个物流公司,把键盘,鼠标等外部设备的输入输出通过这个物流公司送到屏幕或者储存介质里。
为什么printf和scanf能把你的输入显示到控制台或者把你的键盘信息输入到内存中?
因为程序启动默认打开了stdin,stdout,stderr三个标准流。
在c语言文档中对scanf有这样的描述:从stdin标准流中读取…
4.文件操作的实现
4.1文件操作的原理
★★★文件操作需要FILE*,FILE本质上是个结构体,里面包含了需要的流,文件指针等信息★★★
在vs2013之前的版本能看到FILE结构体内部的信息,但在之后的版本已经看不到了。在编译器中输入FILE;然后右键转到声明就可以看到具体底层信息了。
4.1文件指针FILE*
文件操作必须要让程序知道要操作的是哪个文件,所以必须要要文件的地址,需要把这个文件的地址存在FILE*类型的文件指针中。文件指针指向这个指针在内存中的起始地址。
标准流的类型也是FILE*
5.文件打开与关闭操作方法
★★★文件打开与关闭用fopen与fclose★★★
文件的读写是按照程序的视角!读是往程序中输入,写是程序往文件中输出
5.1文件打开模式
模式 | 功能 |
---|---|
r+ 文本读写 | 文本文件中读写数据,侧重于读 |
w+ 文本读写 | 文本文件中读写数据,侧重于写 |
a+ 文本追加读写 | 文本文件中追加或者读取数据 |
a 文本追加写 | 文本文件末尾追加数据 |
ab 二进制追加 | 二进制文件末尾追加数据 |
ab+ 二进制读写 | 二进制文件中读写数据 |
rb 二进制只读 | 二进制文件中读取数据 |
wb 二进制只写 | 二进制文件中写入数据 |
★★★文件不存在的时候,只要是侧重于 ‘r’ 读 的模式,都会出错
而其他模式都会创建一个新的文件★★★
5.2文件打开方法
FILE* fopen(constchar* filename,const char*mode)
★★★传参的时候两个参数都要加入 “ ” ★★★
5.3文件关闭方法
int fclose(FILE * stream )
5.4文件读写函数
函数 | 功能 |
---|---|
fgetc | 字符输入 |
fputc | 字符输出 |
fgets | 文本行输入 |
fputs | 文本行输出 |
fscanf | 格式化输入 |
fprintf | 格式化输出 |
fread | 二进制输入 |
fwrite | 二进制输出 |
5.文件操作代码案例
5.1打开一个文件,写入一串字符,然后关闭文件
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
FILE* lty = NULL; //定义一个文件指针/流接收打开文件的返回值
//以读写(侧重于写)的模式打开文件,文件路径的\必须用\\,即转义字符
lty=fopen("C:\\Users\\luotianyi\\Desktop\\test.txt", "w+");
if (lty == NULL)
{
perror("fopen"); //判断文件是否打开成功
}
fputs("lty520", lty); //文本行输出,将字符串写进文件
fclose(lty); //文件关闭
lty=NULL;
return 0;
}
5.2打开两个文件,读取一个文件里的一段字符,写到另一个文件里
int main()
{
FILE* lty=fopen("C:\\Users\\luotianyi\\Desktop\\test.txt", "w+"); //打开一个文件
if (lty == NULL)
{
perror("fopen lty");
return 1;
}
FILE* ltyplus=fopen("C:\\Users\\luotianyi\\Desktop\\testplus.txt", "w+"); //打开另一个文件
if (ltyplus == NULL)
{
fclose(lty);
lty = NULL;
perror("fopen lty");
return 1;
}
char a[5] = {0}; //用一个字符串接收读取的内容
while (fgets(a, 5, lty)) //每次读取5个字符,包括\0,读到文件末尾会返回NULL
{
fputs(a,ltyplus); //将字符串里面的内容写入plus文件
fputs("\n", ltyplus); //换行
}
fclose(lty); //关闭文件以及释放指针
fclose(ltyplus);
lty = NULL;
ltyplus = NULL;
return 0;
}
6.文件指针/文件光标位置
★★★读写文件的过程中,光标会一直往后走,也就是文件指针会一直往后走,如果要即写即读,写完后没有关闭文件重新打开,指针就会停留在文件数据的末尾,导致无法读取文件,所以需要对文件指针进行操作★★★
SEEK_SET
int fseek ( FILE * stream, long int offset, int origin ) | 设置指针偏移位置,3个参数,第三个参数有3个选项 |
---|---|
long int offset | 相较于int origin的偏移量 |
SEEK_SET | 设置指针到文件开头 |
SEEK_CUR | 设置指针到当前位置偏移量 |
SEEK_END | 设置指针到文件末尾 |
long int ftell ( FILE * stream ) | 返回指针相对于起始位置的偏移量 |
void rewind ( FILE * stream ) | 将指针设置到起始位置 |
6.1设置文件指针代码举例
int main()
{
FILE * ltyy=fopen("C:\\Users\\luotianyi\\Desktop\\test.txt", "r+"); //打开文件,内容为:lty520
if (ltyy == NULL)
{
perror("fopen ltyy");
return -1;
}
char a = 0; //每次获取一个字符,指针往后走1字节
a = fgetc(ltyy);
printf("%c",a);
a = fgetc(ltyy);
printf("%c", a);
a = fgetc(ltyy);
printf("%c", a);
a = fgetc(ltyy);
printf("%c", a);
printf("\n\n", a);
fseek(ltyy,1, SEEK_SET); //对ltyy指针以文件开头设置偏移量为1
char b[10] = { 0 };
fscanf(ltyy,"%s",b); //输入偏移之后的字符串到 b
printf("%s\n", b);
fprintf(stdout,"%s",b); //将b的内容用标准输出流输出到屏幕
fclose(ltyy);
ltyy = NULL;
return 0;
}
7.scanf,fscanf,sscanf///printf,fprintf,sprintf的区别
int scanf ( const char * format, … ) | 从标准输入中读取格式化数据 |
---|---|
int printf ( const char * format, … ) | 将格式化数据打印到标准输出 |
int fscanf ( FILE * stream, const char * format, … ) | 从流中读取格式化数据 |
int fprintf ( FILE * stream, const char * format, … ) | 将格式化数据写入流 |
int sscanf ( const char * s, const char * format, …) | 从字符串中读取格式化数据 |
int sprintf ( char * str, const char * format, … ) | 将格式化数据写入字符串 |