目录
2.2.3 fgets(【地址】,【获取长度】【文件指针】)
2.2.7 fread(【地址】,【字节大小】,【个数】,【文件指针】)
2.2.8 fwrite(【地址】,【字节大小】,【个数】,【文件指针】)
2.3.1 fseek(【文件指针】,【偏移量】,【SEEK_CUR / SEEK_END / SEEK_SET】)
引入
在运行一个程序的时候,我们输入的数据只能在这个程序运行的时候存在,而当我们想要在下次运行的时候在用到这份数据,却又要重新输入,这个时候我们就引入文件存储,使用文件我们可以将数据直接存放在电脑的硬盘上,做到了数据的持久化。
1.文件
程序文件 | 包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe) |
数据文件 | 文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。 |
2.文件操作
在缓冲文件系统中,文件的概念是“文件类型指针”,简称“文件指针”。文件的打开需要使用文件指针,这是一个结构体FILE,其中保存了一个文件的所有信息(比如:文件位置,文件名……)。
2.1文件打开与关闭
而文件的打开则需要调用下列函数:
2.1.1 fopen(【文件路径】,【打开方式】)
打开方式 | 含义 |
"r" | 只读 |
"w" | 只写 |
"a" | 追加 |
"r+" | 可读写 |
"w+" | 可读写 |
"a+" | 追加,在文件末尾追加 |
"rb" | 以二进制读文件 |
"wb" | 以二进制写文件 |
"ab" | 以二进制追加数据 |
FILE* pf = fopen("data.txt", "r");
- 以读的形式打开文件,若无此文件就打开失败,返回NULL,即pf=NULL。(其他形式若无此文件就新建文件,并返回地址)
2.1.2 fclose(【文件指针】)
fclose(pf);
- 关闭文件(一般与fopen搭配使用)。
2.2 文件读与写
函数名 | 功能 | 返回值 |
fgetc(【文件指针】) | 读取文件指针所指的一个字符 | 成功的话并返回,失败或者读完文件则返回EOF |
fputc(【字符】,【文件指针】) | 将一个字符读入文件指针所指处 | 成功的话就返回该字符,否则返回EOF |
fgets(【地址】,【获取长度】【文件指针】) | 读取文件指针所指的一行字符串 | 成功返回读取的字符串地址,失败或读完文件则返回EOF |
fputs(【字符串】,【文件指针】) | 将一行字符读入文件指针所指处 | 成功返回0,失败返回EOF |
fscanf(【文件指针】,“格式”) | 按格式读取内容到文件里 | 成功返回成功输入的个数,否则EOF |
fprintf(【文件指针】,“格式”) | 按格式输入文件内容 | 成功返回字节数总数,否则返回负数 |
fread(【地址】,【字节大小】,【个数】,【文件指针】) | 按字节读取文件内容 | 成功就返回成功读取/写入的字节数,否则EOF |
fwrite(【地址】,【字节大小】,【个数】,【文件指针】) | 按字节写入内容到文件里 |
2.2.1 fgetc(【文件指针】)
// 在 读 状态下完成
int c = fgetc(pf);
putchar(c);
2.2.2 fputc(【字符】,【文件指针】)
// 在 写 状态下完成
char a = '2';
int t = fputc(a, pf);
putchar(t);
2.2.3 fgets(【地址】,【获取长度】【文件指针】)
// 在 读 状态完成
char str[100];
char *ps = fgets(str, 100, pf);
puts(str);
puts(ps);
2.2.4 fputs(【字符串】,【文件指针】)
// 在 写 状态完成
int n = fputs("666", pf); // 插入"666"
printf("%d", n);
2.2.5 fscanf(【文件指针】,“格式”)
// 在 写 模式下进行
char s1[100];
char s2[100];
int n = fscanf(pf, "%s %s", s1,s2); // 获取第一个空格前和第二个空格前的字符串赋值给s1,s2
printf("s1:%s\ns2:%s\nn:%d\n", s1, s2, n);
2.2.6 fprintf(【文件指针】,“格式”)
// 在 写 模式进行
char s[10] = "hehe";
int n = 6;
int m = fprintf(pf, "%s%d", s, n); // 返回字节总数
printf("%d\n", m);
2.2.7 fread(【地址】,【字节大小】,【个数】,【文件指针】)
// 在 写 模式下进行
char t[20];
int n = fread(t, sizeof(int), 5, pf); // 返回个数5
t[sizeof(int) * 5-1] = '\0'; // 因为不会自己加'\0',所以需要手动添加
printf("%d\n%s\n", n, t);
2.2.8 fwrite(【地址】,【字节大小】,【个数】,【文件指针】)
// 在 写 模式下进行
char t[10] = "哈哈哈6";
int n = fwrite(t, sizeof(char), strlen(t), pf); // 返回 strlen(t) 长度
printf("%d\n", n);
2.3 对文件指针的操作
我们知道,每调用一次读写操作的函数,文件指针都会自动往后走一位或移动,方便我们继续往后读写操作,那如果我们想对文件指针进行控制以便更好的对文件进行管理,该如何操作呢?有没有可以控制文件指针移动的方法呢?C语言里就提供了下列函数可对文件指针进行调控。
2.3.1 fseek(【文件指针】,【偏移量】,【SEEK_CUR / SEEK_END / SEEK_SET】)
- 对文件指针进行位置调整,SEEK_CUR表示当前位置,SEEK_END表示文件末尾,SEEK_SET表示文件开始
// 任意模式下进行
fseek(pf, 2, SEEK_SET); // 成功返回0,否则返回非零值
char c = fgetc(pf);
putchar(c);
2.3.2 ftell(【文件指针】)
- 告诉文件指针位置(从0开始)
// 任意模式下进行
int n = ftell(pf); // 返回文件指针位置(从0开始)
printf("%d\n", n);
2.3.3 rewind(【文件指针】)
- 让文件指针回到文件的起始位置
// 任意模式下进行
fseek(pf, 2, SEEK_SET); // 从开头偏移2位,
char c = fgetc(pf);
putchar(c);
rewind(pf); // 回到文件开头
c = fgetc(pf);
putchar(c);
3.文件结束的判定
3.1判定文件结束
函数 | 读完文件的返回值 |
fgetc | 返回EOF |
fgets | 返回NULL |
函数 | 判定文件结束的方法 |
fscanf | 实际返回值小于读取值 或者 返回值为EOF |
fread |
ps:使用fscanf()函数时,推荐使用字符,不推荐用字符数组作为载体,容易越界(上述是错误实例,因为 fscanf() 函数读文本里的内容时,碰到空格就才会停止读取,这样就会导致读取的内容过长或过短,所以赋值时很容易超出数组长度),
这里有一个明显的错误,就是读的文件必须是二进制文件,不然就是像上面这样的乱码内容,所以注意:fread()读的是二进制文本
3.2 判断文件是否结束函数 feof()
函数名 | 返回值 | |
feof(【文件指针】) | 成功:返回非零 | 失败:返回0 |
FILE* pFile;
int n = 0;
pFile = fopen("random.txt", "r");
if (pFile == NULL)
perror("Error opening file");
else
{
while (fgetc(pFile) != EOF)
{
++n;
}
if (feof(pFile))
{
puts("文件已读完");
printf("被读取的总字节数: %d\n", n);
}
else
puts("未到达文件末尾。");
fclose(pFile);
}
解释:正常读完文件,feof返回的值就是非零,执行if语句,如果在while中途跳出循环,则未到达文件末尾,执行else语句。
但是!
牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。
- 文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
例如:
fgetc 判断是否为 EOF .
fgets 判断返回值是否为 NULL .
- 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
例如:
fread判断返回值是否小于实际要读的个数。
4.文件缓冲区
在c语言标准中,我们数据区输入的数据文件不会立刻马上输出到磁盘里,内存会为其开辟一段空间,他会在空间里暂留一段时间,等到空间装满时再全部输出到磁盘里。所以我们称这个部分空间为文件缓冲区。缓冲区的大小根据C编译系统来分配决定。
如图所示
下面实例进行验证:
FILE* pf = fopen("test.txt", "w+");
fputs("Hello,", pf);
// 暂停10秒
Sleep(10000);
printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
puts("刷新缓冲区");
fflush(pf);
fputs("bit ", pf);
// 暂停10秒
Sleep(10000);
printf("睡眠10秒-已经写数据了,打开test.txt文件\n");
puts("刷新缓冲区");
fflush(pf);
fclose(pf); // 关闭文件也会刷新缓冲区
pf = NULL;
这里可以得出一个结论:
因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。如果不做,可能导致读写文件的问题。