C语言文件操作
文章目录
什么是文件
文件就是在磁盘上的一段存储空间
。
不同文件的格式是不一样的,也就是说文件存储的数据是不同的。比如 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+ 模式没什么变化。
三、操作文件
(一)写
-
fwrite:一次写入指定字节数
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; }
-
fputs:一次写入一行(但它不会自动加换行,换行需要自己在输入字符串尾巴加\n)
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; }
-
fprintf:格式化写入
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; }
(二)读(注意w和r+模式会擦除内容)
-
fread():一次读指定字节数
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 ...}成功读取
-
fgets():一次读一行
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; }
-
fscanf():格式化读(与fprintf配套使用)
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 */
(三)文件游标指针
为了对读写进行控制,系统为每一个文件设置了一个文件读写游标指针(或称文件读写位置标记),用来指示“接下来要读写的下一个字符的位置”。
一般情况下,在对文本文件进行顺序读写时,文件游标指针指向文件开头,这时进行读操作,就读第一个字符,然后文件游标指针向后移动一个位置,以此类推,遇到文件尾结束。
如果是写操作,则每写完一个数据后,文件游标指针顺序向后移动一个位置,然后下一次写操作时把数据写入新的所指位置,以此类推,直到写完全部数据。
也可以根据需要,人为移动游标指针位置。
-
feof判断文件的游标指针是否位于文件结尾处
int feof( FILE *stream ); //参数为文件指针 //返回值:游标指针没到文件结尾返回 0,到了结尾返回 !0(利用这点可作循环条件)
-
fseek设置文件游标指针的位置
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个字节处
-
ftell返回文件游标指针的当前位置
long ftell( FILE *stream //文件指针 ); //返回文件游标指针当前位置的下标(下标从0开始)