文件就是在磁盘上的一段存储空间。
不同文件的格式是不一样的,也就是说文件存储的数据是不同的。比如 txt(文本文件) 存储的是字符数据,png(图片文件) 存储的是颜色标识数据,exe(可执行文件) 存储的都是代码。当然数据的本质都是二进制的 0和1,不同的文件在宏观上都是使用 后缀 来区分的。
所谓文件操作,就是把文件内容读进程序里,然后根据格式进行解析,进行读写等操作。
FILE *fopen( const char *filepath, const char *mode );
使用上面这个函数来打开一个文件。它的原理是在物理内存开辟一块空间,将磁盘中被选定文件的内容复制过来(本质就是一大堆字符串),然后进行操作。当我们操作文件结束之后,再把复制的这一份更新到磁盘空间,最终完成修改。
FILE* //返回值是一个文件指针,也就是物理内存上这块空间的首地址
fopen //函数名
const char *filepath //参数1,文件的路径(绝对、相对路径),注意绝对路径的\要进行转义
const char *mode //参数2,文件的打开方式
当我们对文件的操作结束后,需要在程序中关闭文件。这一步会将我们修改后的文件更新到磁盘空间,把开辟的操作文件内存空间释放。
int fclose( FILE *stream ); //唯一参数,文件指针
r模式:只读模式
r模式,又称 rt (read text) 模式,通过这种形式打开文件,文件就只能读取,不能修改。且打开的前提要求是文件必须存在,不存在则打开失败,会报错。
w模式:可读可写模式之从头来过
w模式,又称 wt 模式,通过 w 模式打开的文件,首先会自动擦除原数据。比如文件原来有内容,w 模式打开就会先把文件擦除,重新按照操作写入新数据。
而当文件不存在的时候,会创建文件。
a模式:可读可写模式之狗尾续貂
a模式,又称 at 模式(append),通过 a 模式打开的文件,不会擦除原有数据,而是在原有内容后面接着写。比如文件有内容,打开文件内容原封不动,如果写入新内容,就会在原有的尾巴上接着写。
当文件不存在的时候,会创建文件。
三种模式的plus版本
r+模式( r模式plus版本 ),通过这个模式打开文件,可读可写。所以plus之处就是加上了“写”操作。注意前提仍然是文件必须存在。而且 r+ 模式等同 w 模式,都是擦除写。
同理,w+ 和 a+ 模式就是 w 和 a 模式的plus版本。因为plus之处在于加上“写”操作,所以plus版本和以前没什么变化。
rb模式:只读模式
rb(read bit)模式,原理同 rt 模式。(文件必须存在)
wb模式:可读可写模式之从头来过
wb模式,原理同 wt 模式。(文件不存在会创建文件)
ab模式:可读可写模式之狗尾续貂
ab模式,原理同 ab 模式。(文件不存在会创建文件)
三种模式的plus版本
rb+模式( rb 模式plus版本 ),文件可读可写。注意前提仍然是文件必须存在。而且 r+ 模式等同 w 模式,都是擦除写。
同理,wb+ 和 ab+ 模式没什么变化。
size_t fwrite( //返回值是实际写入的字符数(int型),写入失败会返回 0
const void *buffer, //参数1:要写入文件的数据的首地址,可以是字符串、数组、结构体
size_t size, //参数2:sizeof(类型)
size_t count, //参数3:数据数量,参数2与参数3相乘得出写入的字节数
FILE *stream //参数4:文件指针
);
举个栗子:
#include <stdio.h>
#include <string.h>
int main()
{
char* str = "I LOVE YOU !";
FILE* f = fopen("C:\\Users\\13040\\Desktop\\test.txt", "w");
fwrite(str, sizeof(char), strlen(str), f);
fwrite("\n", sizeof(char), 1, f); // 写入回车
fwrite(str, sizeof(char), strlen(str), f);
fclose(f);
return 0;
}
int fputs( const char *str, FILE *stream );
//返回值:成功返回 0,失败返回EOF(-1)
//参数1:输入的字符串(只能输入字符串)
//参数2:文件指针
举个李子:
#include <stdio.h>
#include <string.h>
int main()
{
char* str = "I LOVE YOU !";
FILE* f = fopen("C:\\Users\\13040\\Desktop\\test.txt", "w");
fputs(str, f);
fputs("\n", f);
fputs(str, f);
fclose(f);
return 0;
}
int fprintf(
FILE *stream, //文件指针
const char *format [,//和printf函数一样的参数要求
argument ]...
);
举个梨子:
#include <stdio.h>
#include <string.h>
int main()
{
FILE* f = fopen("C:\\Users\\13040\\Desktop\\test.txt", "w");
fprintf(f, "%d,%s,%lf", 12, "hello", 12.34);
fclose(f);
//写入内容:12,hello,12.340000
return 0;
}
size_t fread( //返回值是实际读出的字节数
void *buffer, //参数1:我们自定义的字符数组,文件读出来的内容装在这里
size_t size, //参数2:sizeof(类型)
size_t count, //参数3:数据数量,参数2与参数3相乘等于读出的字节数
FILE *stream //参数4:文件指针
);
举个例子:
#include <stdio.h>
#include <string.h>
int main()
{
char str[15] = { 0 };
FILE* f = fopen("C:\\Users\\13040\\Desktop\\test.txt", "r");
fread(str, sizeof(char), 12, f);
puts(str); //I LOVE YOU !
/*while (fread(str, sizeof(char), 1, f))
{
printf("%s", str);// I LOVE YOU !
}*/
fclose(f);
return 0;
}
fread()读写结构体:
#include <stdio.h>
struct Node
{
int id;
char name[10];
short age;
double score;
};
int main()
{
//写操作
struct Node stu1 = { 13,"张三",20,88.8 };
FILE* f = fopen("C:\\Users\\13040\\Desktop\\test.txt", "w");
fwrite(&stu1, sizeof(stu1), 1, f);
fclose(f);
//读操作
struct Node stu2;
FILE* g = fopen("C:\\Users\\13040\\Desktop\\test.txt", "r");
fread(&stu2, sizeof(stu1), 1, g);
fclose(f);
return 0;
}
//调试发现:stu2{id=13 name=0x000000af711cfc0c "张三" age=20 ...}成功读取
char *fgets( char *str, int n, FILE *stream );
//返回值:就是str的地址
//参数1:读出来的数据装在哪儿
//参数2:最大的读取量,不要超过参数1的长度
//参数3:文件指针
举个例子:
#include <stdio.h>
#include <string.h>
int main()
{
char str[20] = "";
FILE* f = fopen("C:\\Users\\13040\\Desktop\\test.txt", "r");
fgets(str, 20, f);
puts(str);
fclose(f);
return 0;
}
int fscanf(
FILE *stream, //文件指针
const char *format [,//和scanf函数一样的参数要求
argument ]...
);
举个例子:
#include <stdio.h>
#include <string.h>
int main()
{
int a = 0;
char str[20] = { 0 };
double b = 0;
FILE* f = fopen("C:\\Users\\13040\\Desktop\\test.txt", "r");
//先w模式写入,记住字符串连接数字必须用空格隔开,要不然读取的时候字符串不遇空格不停
//fprintf(f, "%d,%s %lf", 12, "hello", 12.34);
//怎么用fprintf写的,fscanf就得怎么读,格式字符串必须保持一致
fscanf(f, "%d,%s %lf", &a, str, &b);
printf("%d\n", a);
printf("%s\n", str);
printf("%lf", b);
fclose(f);
return 0;
}
/*
12
hello
12.340000
*/
为了对读写进行控制,系统为每一个文件设置了一个文件读写游标指针(或称文件读写位置标记),用来指示“接下来要读写的下一个字符的位置”。
一般情况下,在对文本文件进行顺序读写时,文件游标指针指向文件开头,这时进行读操作,就读第一个字符,然后文件游标指针向后移动一个位置,以此类推,遇到文件尾结束。
如果是写操作,则每写完一个数据后,文件游标指针顺序向后移动一个位置,然后下一次写操作时把数据写入新的所指位置,以此类推,直到写完全部数据。
也可以根据需要,人为移动游标指针位置。
int feof( FILE *stream );
//参数为文件指针
//返回值:游标指针没到文件结尾返回 0,到了结尾返回 !0(利用这点可作循环条件)
int fseek(
FILE *stream, //参数1:文件指针
long offset, //参数2:设置文件游标指针指的位置
int origin //参数3:具体位置
);
巨蟹李子:
fseek(f, 0L, SEEK_SET) //设置游标指针指向文件起始位置
fseek(f, 10L, SEEK_SET) //设置游标指针指向起始位置 向右 挪动10个字节处
fseek(f, 10L, SEEK_CUR) //设置游标指针在当前位置 向右 挪动10个字节处
fseek(f, -10L, SEEK_CUR)//设置游标指针在当前位置 向左 挪动10个字节处
fseek(f, 0L, SEEK_END) //设置游标指针指向文件结尾位置(最后一个字符后面)
fseek(f, -10L, SEEK_END)//设置游标指针指向结尾 向左 挪动10个字节处
long ftell(
FILE *stream //文件指针
);
//返回文件游标指针当前位置的下标(下标从0开始)