比如:当我们写了一个通讯录,运行起来后可以在里头 增减数据,而一旦退出程序后,其中的数据就会不在了,只 能在下次重新输入数据,这样的通讯录明显不符合我们的需求。
So当我们需要将数据做到持久化时,就需要使用文件将数据存放在电脑的硬盘上
一.什么是文件
1.1定义
磁盘上的文件是文件
在程序设计中,功能性的将文件一般分为:程序文件,数据文件
- 程序文件:包括 源程序文件(后缀为 .c),目标文件(windoes环境后缀为 .obj),可执行文件(windoes环境后缀为 .exe)
- 数据文件:文件的内容不一定是程序,而是程序在运行时读写的数据, 比如程序运行需要从中读取数据的文件,或输出内容的文件。
1.2文件名
一个文件需要一个唯一的文件标识,以便进行识别和引用
文件名:文件路径+文件名主干+文件后缀
如:c:\code\test.txt
二.文件的打开与关闭
2.1文件指针
每个被使用的文件都会在内存中开辟出一个相应的文件信息区,其用来存放文件的相关信息(如文件名、文件状态 及 文件当前位置 等)。这些信息是保存在一个结构体变量中的,该结构体类型是由系统申明的,其名为 FILE
注意:文件和文件信息区是关联的,文件已改变则文件信息区也会发生改变
注意:
- FILE结构在不同的C编译器下设计和实现可能是有所差异的,但是大同小异
- 每当打开一个文件时,系统会根据文件的情况自动创建一个 FILE 结构的变量,并填充其中的信息。我们不用关其细节
- 一般可通过一个 FILE 的指针来维护这个 FILE 结构的变量
创建一个FILE*的指针变量:
FILE* pf; //文件指针变量
//定义 pf 是一个指向 FILE 类型的指针变量,可以使 pf 指向某个文件的文件信息区(是一个结构体变量,可通过该文件信息区的信息就能够访问该文件。
可通过文件指针变量找到与其相关联的文件
2.2文件的打开与关闭
文件在读写前应该先用 fopen打开文件,使用结束后用 fclose关闭文件
fopen
- 如果文件成功打开,该函数将返回指向FILE对象的指针;失败则返回空指针
方式 | 描述 |
"r" | 打开一个已有的文本文件,只允许读取文件;如果这个文件不存在或未找到,则打开失败,报错 |
"w"
| 打开一个空文件,为写文件;如果文件不存在,则会创建一个新文件;如果这个文件里有内容,该文件内容将被销毁 |
"a" | 追加写入文件;如果文件不存在,则会创建一个新文件。 |
"r+" | 打开一个文本文件,允许读写文件。 |
"w+" | 创建一个空文件;允许读写文件。如果文件已存在,则文件内容被销毁;如果文件不存在,则会创建一个新文件。 |
"a+" | 在文件尾进行读写 ;如果文件不存在,则会创建一个新文件。读取会从文件的开头开始,写入则只 能是追加模式。 |
fclose
#include<stdio.h>
int mainn()
{
FILE* pf = fopen("test.txt","w");
if(pf == NULL)
{
perror("fopen");
return 1;
}
//开写文件
//。。。。。。。。。。。。
//关闭文件
fclose(pf);
pf = NULL;
}
三.文件的顺序读写
顺序读写函数
功能 | 函数名 | 适用于 |
字符输入函数 | fgetc | 所有输入流 |
字符输出函数 | fputc | 所有输出流 |
文本行输入函数 | fgets | 所有输入流 |
文本行输出函数 | fputs | 所有输出流 |
格式化输入函数 | fscanf | 所有输入流 |
格式化输出函数 | fprintf | 所有输出流 |
二进制输入 | fread | 文件 |
二进制输出 | fwrite | 文件 |
fputc(字符输出函数)
#include <stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
// 写文件
fputc('b', pf);
fputc('y', pf);
fputc('e', pf);
// 关闭文件
fclose(pf);
pf = NULL;
return 0;
}
运行后不会直接看见bye.
而当我们打开文本后可以看到:
fgetc(字符输入函数)
- 从流中读取一个字符,位置标识符向前移动一(字符必须为一个无符号字符)
- 参数为 指向标识输入流的FILE对象的指针。
- 如果读取成功会返回相应的ASCII码值,读取失败它会返回一个EOF。
//从文件里读取
#include <stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
// 写文件
int ret = fgetc(pf);
printf("%c\n",ret);
ret = fgetc(pf);
printf("%c\n",ret);
ret = fgetc(pf);
printf("%c\n",ret);
// 关闭文件
fclose(pf);
pf = NULL;
return 0;
}
//从标准输入流 (键盘)读取
#include <stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
// 写文件
int ret = fgetc(stdin);
printf("%c\n",ret);
ret = fgetc(stdin);
printf("%c\n",ret);
ret = fgetc(stdin);
printf("%c\n",ret);
// 关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fputs(文本行输出函数)
#include <stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件 ——按照行来写
fputs("abcdef\n", pf);
fputs("zxcvbnm\n", pf);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fgets(文本行输入函数)
- 读取时由于最后会使用一个进行\0的读取,所以一次最多读取n-1个
#include <stdio.h>
int main()
{
char arr[10] = {0}; // 存放处
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件 - 按照行来读
fgets(arr, 4, pf);
printf("%s\n", arr);
fgets(arr, 4, pf);
printf("%s\n", arr);
// 关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fprintf(格式化输出函数)
#include <stdio.h>
struct S
{
char arr[10];
int num;
float wb;
};
int main()
{
struct S s = { "qazxsw", 10, 8.2f };
// 对格式化的数据进行 写文件
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
// 写文件
fprintf(pf, "%s %d %f", s.arr, s.num, s.wb);
// 关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fscanf(格式化输入函数)
#include <stdio.h>
struct S
{
char arr[10];
int num;
float wb;
};
int main()
{
struct S s = { "qazxsw", 10, 8.2f };
// 对格式化的数据进行 写文件
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
// 读文件
fscanf(pf,"%s %d %f", s.arr, &(s.num), &(s.wb));
//打印
printf("%s %d %f\n", s.arr ,s.num ,s.wb) ;
// 关闭文件
fclose(pf);
pf = NULL;
return 0;
}
//qazxsw 10 8.200000
fwrite(二进制输出)
#include <stdio.h>
struct S
{
char arr[10];
int num;
float wb;
};
int main()
{
struct S s = { "qazxsw", 10, 8.2f };
//二进制形式 写
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
// 写文件
fwrite(&s, sizeof(struct S), 1, pf) ;
// 关闭文件
fclose(pf);
pf = NULL;
return 0;
}
在记事本中打开test.txt,可以看到除了字符串,其他是乱码:
得要搭配fread函数来看
fread(二进制输入)
#include <stdio.h>
struct S
{
char arr[10];
int num;
float wb;
};
int main()
{
struct S s = { "qazxsw", 10, 8.2f };
//二进制形式 读
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
// 读文件
fread(&s, sizeof(struct S), 1, pf) ;
printf("%s %d %f",s.arr ,s.num ,s.wb) ;
// 关闭文件
fclose(pf);
pf = NULL;
return 0;
}
//qazxsw 10 8.200000
小结:fwite写,fread读
流:
c语言程序,只要运行,就默认打开3个流(均为FILE*):
stdin——标准输入流——从键盘 输入
stdout——标准输出流——输出至 屏幕
stderr——标准错误流——输出至 屏幕
例子:使用stdout下
scanf,printf和fscanf,fprintf区别
scanf 针对标准输入的格式化的输入语句 —— stdin
fscanf 针对所有输入流的格式化的输入语句 —— stdin/文件
printf 针对标准输出的格式化的shuchuyuju输出语句 —— stdout
fprintf 针对所有输入流的格式化的输出语句 —— stdout/文件
四.文件的随机读写
4.1 fseek
- 偏移量为负数——表示向后多少;正数——表示向前多少
#include <stdio.h>
int main(void)
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
// 读取文件
int ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
// 关闭文件
fclose(pf);
pf = NULL;
return 0;
}
//q a z
当加入fseek函数:
#include <stdio.h>
int main(void)
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
// 读取文件
int ch = fgetc(pf);
printf("%c\n", ch);
fseek(pf ,-1 ,SEEK_CUR);//往后1个字节
ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
// 关闭文件
fclose(pf);
pf = NULL;
return 0;
}
//q q a
4.2 ftell
#include <stdio.h>
int main(void)
{
FILE* pf = fopen("test1.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
// 读取文件
int ch = fgetc(pf);
printf("%c\n", ch);
fseek(pf ,-2 ,SEEK_END);
ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
int ret = ftell(pf);
printf("%d\n",ret);
// 关闭文件
fclose(pf);
pf = NULL;
return 0;
}
//a e f 6
4.3 rewind
#include <stdio.h>
int main(void)
{
FILE* pf = fopen("test1.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
// 读取文件
int ch = fgetc(pf);
printf("%c\n", ch);
fseek(pf ,-2 ,SEEK_END);
ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
int ret = ftell(pf);
printf("%d\n",ret);
//让文件回到起始位置
rewind(pf);
ch = fgetc(pf);
printf("%c\n", ch);
// 关闭文件
fclose(pf);
pf = NULL;
return 0;
}
//a e f 6 a