文章目录
1. 文件
1. 数据文件
- 程序运行时需要读取数据的文件,或者输出数据的文件叫数据文件
2. 文件指针
- 当我们打开一个文件时,系统会在内存开辟一个文件信息区,这个文件信息区放着文件的相关信息
- 文件信息区其实是一个结构体变量,结构体变量中放着文件的相关信息,通过文件信息区就可以访问该文件,而文件指针就会指向文件信息区首元素的地址,那么通过文件指针可以直接找到与它相关的文件
3.文件名
文件名包含3部分:文件路径+文件名主干+文件后缀
2. 文件的打开和关闭
> #include <stdio.h>
int main()
{
//打开
FILE* p = fopen("file.txt", "w");
if (p == NULL)
{
perror("file_fopen");
return 1;
}
//使用
//关闭
fclose(p);
p = NULL;
}
- 文件打开失败返回NULL
- 第一个参数是文件名,第二个参数是以什么方式打开即文件的使用方式,以w(写的形式)形式打开
- 如果没有这个文件,会创建一个新的文件,即使有这个文件,它也会销毁这个文件,创建一个新的文件,原来文件的内容也会被销毁
3. 文件的顺序读写
1. 字符输出函数
> #include <stdio.h>
int main()
{
//打开
FILE* p = fopen("file.txt", "w");
if (p == NULL)
{
perror("file_fopen");
return 1;
}
//使用
int i = 0;
for (i = 0; i < 26; i++)
{
fputc(97 + i, p);
}
//关闭
fclose(p);
p = NULL;
}
- 第一个参数传字符或字符的ascii值,第二个传文件指针
2.字符输入函数
#include <stdio.h>
int main()
{
//打开
FILE* p = fopen("file.txt", "r");
if (p == NULL)
{
perror("file_fopen");
return 1;
}
//使用
int i = 0;
for (i = 0; i < 26; i++)
{
printf("%c", fgetc(p));
}
//关闭
fclose(p);
p = NULL;
}
-
fgetc的参数是一个文件指针,返回字符的ascii值
-
至于为什么不打印aaaaaaaaa…
-
为什么不打印aaaaaaaaa…的原因
每次打开文件时,都会有一个文件指针指向文件内容
- 注意这个文件指针并不是FILE* p = fopen(“file.txt”, “r”);这里的指针p,指针p是指向文件信息区的,而这个指针是一个全新的指向文件内容的指针,
- 每次调用fgetc()时,文件指针都会向后指向下一个元素,所以输入到内存的字符不是同一个
3.文本行输出函数
#include <stdio.h>
int main()
{
//打开
FILE* p = fopen("file.txt", "w");
if (p == NULL)
{
perror("file_fopen");
return 1;
}
//使用
char arr[] ="aaa";
fputs(arr, p);
//关闭
fclose(p);
p = NULL;
}
4.文本行输入函数
#include <stdio.h>
int main()
{
//打开
FILE* p = fopen("file.txt", "r");
if (p == NULL)
{
perror("file_fopen");
return 1;
}
//使用
char arr[20] = { 0 };
fgets(arr, 5, p);
printf("%s", arr);
//关闭
fclose(p);
p = NULL;
}
- 第一个参数为字符指针,第一个参数为最大拷贝多少个字符,第三个为文件指针
- 使用时要注意实际向str拷贝的num-1个字符,因为str要末尾要有\0占一个字符
4.格式化输出函数
- 对于fprintf可以先仿照printf来写,它们参数是只差一个文件指针,最后再补上文件指针即可
#include <stdio.h>
struct s
{
char name[20];
int age;
};
int main()
{
struct s s = { "zhangsan",30 };
//打开
FILE* p = fopen("file.txt", "w");
if (p == NULL)
{
perror("file_fopen");
return 1;
}
//使用
fprintf(p,"%s %d", s.name, s.age);
//关闭
fclose(p);
p = NULL;
}
5.格式化输入函数
- 同样是先仿写scanf,再写fsanf
#include <stdio.h>
struct s
{
char name[20];
int age;
};
int main()
{
struct s s = { 0 };
//打开
FILE* p = fopen("file.txt", "r");
if (p == NULL)
{
perror("file_fopen");
return 1;
}
//使用
fscanf(p, "%s %d", s.name, &s.age);
//关闭
printf("%s %d", s.name, s.age);
fclose(p);
p = NULL;
}
6.二进制输入
#include <stdio.h>
struct s
{
char name[20];
int age;
};
int main()
{
struct s s = { "lisi",20 };
FILE * p = fopen("file.txt", "wb");
if (p == NULL)
{
perror("file_fopen");
return 1;
}
//使用
fwrite(&s, sizeof(struct s), 1, p);
//关闭
fclose(p);
p = NULL;
}
7.二进制输入
struct s
{
char name[20];
int age;
};
int main()
{
struct s s = { 0};
FILE * p = fopen("file.txt", "rb");
if (p == NULL)
{
perror("file_fopen");
return 1;
}
//使用
fread(&s, sizeof(struct s), 1, p);
printf("%s %d", s.name, s.age);
//关闭
fclose(p);
p = NULL;
}
4. 流的概念
- 流是一个抽象的概念
- 我们将数据传输到文件,屏幕等外部设备时,我们抽象出来一个流,让流去实现如何将数据传到外部设备上去,我们只负责将数据写到流里,从流里拿数据
- C语言默认打开三个流:屏幕:标准输出流(stdout),键盘:标准输入流(stdin),屏幕:标准错误流(stderr),三者类型均为FILE*
5.scanf,sprintf
- scanf将字符串转化为格式化数据
- sprintf将格式化数据转化为字符串
#include <stdio.h>
struct s
{
char name[20];
int age;
};
int main()
{
struct s s = { "lisi",20};
char arr[20] = { 0 };
sprintf(arr, "%s %d", s.name, s.age);
printf("%s", arr);
printf("\n");
struct s tmp = { 0 };
sscanf(arr, "%s %d", tmp.name, &tmp.age);
printf("%s %d", tmp.name, tmp.age);
}
6. 文件的随机读写
1. feek
- 三者分别表示文件开始位置,文件指针当前位置,文件末尾
- 作用为对指向文件内容的指针进行偏移进行
- 假设文件里有abcdef
int main()
{
FILE*p = fopen("file.txt", "r");
if (p == NULL)
{
perror("file_fopen");
return 1;
}
//使用
int ch = 0;
ch = fgetc(p);//a
printf("%c", ch);
ch = fgetc(p);//b
printf("%c", ch);
ch = fgetc(p);//c
printf("%c", ch);
ch = fgetc(p);//d
printf("%c", ch);//此时指向e
fseek(p, -2, SEEK_CUR);
ch = fgetc(p);//希望打印c
printf("%c", ch);
//关闭
fclose(p);
p = NULL;
}
2.ftell
- 告诉我指针偏移量
int main()
{
FILE*p = fopen("file.txt", "r");
if (p == NULL)
{
perror("file_fopen");
return 1;
}
//使用
int ch = 0;
ch = fgetc(p);//a
printf("%c", ch);
ch = fgetc(p);//b
printf("%c", ch);
ch = fgetc(p);//c
printf("%c", ch);
ch = fgetc(p);//d
printf("%c", ch);//此时指向e
fseek(p, -2, SEEK_CUR);
ch = fgetc(p);//希望打印c
printf("%c", ch);
//打印完后指向d,相对起始位置偏移了3
printf("%d", ftell(p));
//关闭
fclose(p);
p = NULL;
}
3.rewind
- 将文件指针回到起始位置
int main()
{
FILE*p = fopen("file.txt", "r");
if (p == NULL)
{
perror("file_fopen");
return 1;
}
//使用
int ch = 0;
ch = fgetc(p);//a
printf("%c", ch);
ch = fgetc(p);//b
printf("%c", ch);
ch = fgetc(p);//c
printf("%c", ch);
ch = fgetc(p);//d
printf("%c", ch);//此时指向e
fseek(p, -2, SEEK_CUR);
ch = fgetc(p);//希望打印c
printf("%c\n", ch);
//打印完后指向d,相对起始位置偏移了3
printf("%d\n", ftell(p));
rewind(p);
//偏移量变为0
printf("%d\n", ftell(p));
//关闭
fclose(p);
p = NULL;
}
7.文本文件和二进制文件
- 根据数据的组织形式,数据文件被称为文本文件或者二进制文件。
- 数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。
- 如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件
8.文件读取结束的判定
- 用feof,ferror来进行判定,当读取文件结束后,feof()判断结束原因是否为文件读取结束,ferrof判断结束原因是否为发生错误而结束
9.文件缓冲区
- 从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。
-
- 如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。
- 缓冲区的大小根
据C编译系统决定的。