文件操作
之前都是在内存中运行的代码,
调试窗口一关,数据就销毁了,不管是栈区还是堆区静态区的数据,
因为他们都是存储在内存上的,
要学会文件操作,临时存储数据的选项。
数据库,存储数据
程序在内存中执行,硬盘上执行的是文件,
-
在程序设计中,谈到的文件是:程序文件、数据文件(从文件功能的角度来分类的)。
- 程序文件
-
源文件(.c)、目标文件(windows环境后缀为 .obj) 、可执行文件(windows环境后缀为.exe)
- 数据文件
文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。
在终端上进行,以终端为对象的,从终端的键盘输入数据,运行显示到显示器上。//这句话有歧义。
在终端上运行的是,从内存中读取的文件,
看一下,之前写的工程,文件名后缀分布。
2.3 文件名
一个文件的唯一的文件标识,以便用户识别和引用。
文件名包含3部分:文件路径+文件名主干+文件后缀
c:\code\test.txt
缓冲文件系统中的,
每一个被使用的文件都在内存中开辟了一个相应的文件信息区,存放文件的相关的信息。(文件的名字,文件状态及文件当前的位置)。信息保存在一个结构体变量中,该结构体类型是有系统声明的,名字是 FILE
3.1 文件指针
- 创建一个FILE*的 指针变量
FILE* pf;//文件指针变量
使pf指向某个文件的文件信息区。(是一个结构体变量)。通过该文件信息区中的信息就能访问该文件。
- 流的概念
stream,流
——高度抽象的概念。
程序要在不同的环境中被使用,比如:屏幕、硬盘、U盘上、光盘、网络、软盘上,
为了应对这种现象,使用stream来做过度,程序在书写的过程中,不用专门的编写代码,应对不同环境
C语言程序,只要运行起来,就默认打开的3个流:(FILE*)
stdin - 标准输入流 - 键盘
stdout - 标准输出流 - 屏幕
stderr - 标准错误流 - 屏幕
- fopen()
int main()
{
FILE* pf = fopen("test.txt","r");//只读不会新建
if(pf == NULL)
{
perror("pf");
return 1;
}
FILE* pf1 = fopen("test.txt","w");//没有的话,会新建一个文件。
if(pf1 == NULL)
{
perror("pf1");
return 1;
}
return 0;
}
使用的方法下面有:就是还含有包不包括新建文件。
常用
文件使用方式 | 含义 | 如果指定文件不存在 |
---|---|---|
“r“(只读) | 为了输入数据,打开一个已经 存在的文本文件 | 出错 |
”w“(只写) | 为了输出数据,打开一个文本文件 | 建立一个新的文件 |
”a“(追加) | 向文本文件尾添加数据 | 建立一个新的文件 |
“a+”(追加,新建) | 打开一个文件,在文件尾进行读写 | 建立一个新的文件 |
- 文件和硬盘的关系
fopen(),函数的读取是相对于,内存来言的。
- fgetc() - 的使用
int main()
{
FILE* pf = fopen("test.bat", "r");
if (pf == NULL)
{
perror("fopen:");
return 1;
}
//读取文件
int ret = fgetc(pf);//这里是int,为什么?这是规定。
//printf("%d\n", ret);
printf("%c\n", ret);//%c - 打印还能理解。
ret = fgetc(pf);
printf("%c\n", ret);
ret = fgetc(pf);
printf("%c\n", ret);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
- fputc()
int main()
{
fputc('w', stdout);
fputc('h', stdout);
fputc('y', stdout);
//直接打印一排的字母 - why
return 0;
}
stdin - 标准输入流 - 键盘
stdout - 标准输出流 - 屏幕
stderr - 标准错误流 - 屏幕
- fgetc()
int ret = fgetc(stdin);
printf("%c\n", ret);
ret = fgetc(stdin);
printf("%c\n", ret);
ret = fgetc(stdin);
printf("%c\n", ret);
先输入内容,才能在屏幕上输出,
- fscanf() 和 fprintf()
int input = 0;
fscanf(stdin, "%d", &input);
fprintf(stdout, "%d", input);
fwrite(&a,sizeof(int),1,pf);
// 元素多大, 几个整型
// 从&a写到pf的地址处。
- 拷贝文件
int main()
{
FILE* pfread = fopen("test.txt", "r");
if (pfread == NULL)
{
perror("pfread");
return 1;
}
FILE* pfwrite = fopen("tesst1.txt", "w");
if (pfwrite == NULL)
{
fclose(pfread);
pfread = NULL;
perror("pfwrite");
return 1;
}
int ch = 0;
while ((ch = fgetc(pfread)) != EOF)
{
fputc(ch,pfwrite);
}
fclose(pfread);
pfread = NULL;
fclose(pfwrite);
pfwrite = NULL;
return 0;
}
因为,fopen()参数是“r”的话,不会新建一个文件。
针对这三种不同的函数
-
scanf(“%d",&input) - 针对标准输入的格式化的输入语句 - stdin
-
fscanf(stream,“%d”,&input) - 针对所有输入流的格式化的输入语句 - stdin / 文件
-
sscanf() - 从一个字符串中读取一个格式化的数据
-
printf(“%d\n”,input) - 针对标准输出的格式化输出语句 - stdout
-
fprintf(stream,“%d”,input) - 针对所有输出流的格式化输出语句 - stdout / 文件
-
sprintf() - 把一个格式化的数据,转换成字符串
//用结构举例说明
struct S
{
char arr[10];
int a;
double b;
};
int main()
{
int input = 0;
scanf("%d", &input);
printf("%d", input);
//换一种输入和输出的方法
int sinput = 0;
fscanf(stdin,"%d" ,&sinput);
fprintf(stdout,"%d", sinput);
//使用sscanf() and sprintf()
struct S s = { "hello",4,5.5f};
struct S tmp = { 0 };
char buf[100] = { 0 };
//将结构体数据转换成字符串
sprintf(buf, " % s % d % lf", s.arr, s.a, s.b);
printf("%s\n", buf);
//将字符串中的数据转换成一个结构体。
sscanf(&tmp, "%s %d %lf", s.arr, &(s.a),&( s.b));
printf("%s %d %lf", s.arr, s.a, s.b);
return 0;
}
文本文件和二进制文件
根据数据的组织形式,数据文件被称为文本文件或者二进制文件
数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。
FILE*指针相关的相关函数,
- fseek(pf,-2,SEEK_END) - 调整文件指针
第三个参数,可选值:SEEK_END 、 SEEK_CUR 、SEEK_SET,,current当前,,set ,beginning
-
ftell(pf) - 显示偏移量
-
rewind(pf) - 文件指针回到初始位置
文件读取结束的判定
feof()
函数
在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是结束。
而是应用于当前文档读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。
- 文本文件读取是否结束,判断返回值是否为
EOF
(fgetc),或者NULL
,(fgets)
-
fgetc
判断是否为EOF
.fgets
判断返回值是否为NULL
.
- 二进制文件的读取结束判断,判断返回值是否实际要读的个数。
- fread判断返回值是否小于实际要读的个数。
-
相关代码
int main()
{
FILE* pfread = fopen("test.txt", "r");
if (pfread == NULL)
{
perror("pf");
return 1;
}
FILE* pfwrite = fopen("test2.txt", "w");
if (pfwrite == NULL)
{
fclose(pfread);
pfread = NULL;
return 1;
}
//文件打开成功
//读写文件
int ch = 0;
while ((ch = fgetc(pfread)) != EOF)
{
//写文件
fputc(ch, pfwrite);
}
if (feof(pfread))
{
printf("遇到文件结束标志,文件正常结束\n");
}
else if (frerror(pfread))
{
printf("文件读取失败\n");
}
fclose(pfread);
pfread = NULL;
fclose(pfwrite);
pfwrite = NULL;
return 0;
}
- 文件结束判断标志
int c;
FILE* fp = fopen("test.txt", "r");
if (fp == NULL)
{
perror("fp");
return 1;
}
while ((c = fgetc(fp)) != EOF)
{
putchar(c);
}
if (ferror(fp))
puts("\nwhen reading\n");
else if (feof(fp))
puts("\nend of file\n");
fclose(fp);
fp = NULL;
文件缓存区
内存中程序在数据区到硬盘的过程中,输入和输出的过程中,都要走缓存区。
window.hSleep(1000);