文件分类:
文件一般讲两种:程序文件和数据文件;
程序文件:
包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。
数据文件:
包括程序运行时所读写的数据。本篇所涉及的就是数据文件。
文件指针:
想要对文件进行操作,“文件指针”就是一个关键桥梁(亦名:文件类型指针);
文件指针的使用:
FILE* pf;
文件的打开和关闭
在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指
针和文件的关系。
fopen() —— 打开文件;
FILE * fopen ( const char * filename, const char * mode );
fclose() —— 关闭文件;
int fclose ( FILE * stream );
以上结合起来实例:
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf= fopen("test.txt", "w+");
if (pf == NULL)
{
printf("%s\n", strerror(errno));
return;
}
//输入一个字符
fputc('a', pf);
//用完关闭文件
fclose(pf);
pf = NULL;
return 0;
}
注意:这里fputs函数虽然是整行写入,但会覆盖掉原始数据
6.将结构体信息写入文件中:
这里的结构体信息就是格式化的,那么就需要fprintf()函数了
#include<stdio.h>
typedef struct S
{
char name[10];
int age;
}Peo;
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf != NULL)
{
Peo p = { "zhangsan", 18 };
fprintf(pf, "%s %d\n", p.name, p.age);
fclose(pf);
pf = NULL;
}
return 0;
}
7.读取文件信息到结构体变量中:
-
#include<stdio.h> typedef struct S { char name[10]; int age; }Peo; int main() { FILE* pf = fopen("test.txt", "r"); if (pf != NULL) { Peo p = { 0 }; fscanf(pf, "%s %d", p.name, &p.age); printf("%s %d", p.name, p.age); fclose(pf); pf = NULL; } return 0; }
8.二进制写入文件:
- size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
#include<stdio.h>
#include<string.h>
#include<errno.h>
typedef struct S
{
char name[10];
int age;
}Peo;
int main()
{
FILE* pf = fopen("test.txt", "wb+");
if (pf != NULL)
{
Peo p = { "lisi", 19};
fwrite(&p, sizeof(Peo), 1, pf);
fclose(pf);
pf = NULL;
}
return 0;
}
9.读取二进制文件信息:
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
-
#include<stdio.h> typedef struct S { char name[10]; int age; }Peo; int main() { FILE* pf = fopen("test.txt", "rb+"); if (pf != NULL) { Peo p = { 0 }; fread(&p, sizeof(Peo), 1, pf); printf("%s %d\n", p.name, p.age); fclose(pf); pf = NULL; } return 0; }
10.sscanf()函数、sprintf()函数
这两个函数虽然和文件操作关系不大,但是容易与文件操作函数混淆;sscanf()函数:
int sscanf( const char *buffer, const char *format [, argument ] ... );
将一个字符串转化为格式化数据;
#include<stdio.h> typedef struct S { char name[10]; int age; }Peo; int main() { //定义一个字符串 char buffer[] = { "zhansan 19" }; //定义一个结构但不赋值 Peo p = { 0 }; sscanf(buffer, "%s %d", p.name, &p.age); return 0; }
- sprintf()函数:
-
-
int sprintf( char *buffer, const char *format [, argument] ... );
-
将一个格式化数据转化为字符串;
#include<stdio.h> typedef struct S { char name[10]; int age; }Peo; int main() { //定义一个结构 Peo p = { "zhangsan",19}; //定义一个字符串 char buffer[50] = { 0 }; sprintf(buffer, "%s %d\n", p.name, p.age); return 0; }
-
文件的随机读写
所谓的随机读写,其实就是指定我们想要读写的位置。
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
printf("%s\n", strerror(errno));
return;
}
//开始多次读取
//定位指针:比如要读取从头开始向后偏移 2 个单位的一个字符
fseek(pf, 2, SEEK_SET);
int ch = fgetc(pf);
printf("%c\n", ch);
//第二次读取:要拿到当前文件指针所处位置向后偏移5个单位的字符
fseek(pf, 5, SEEK_CUR);
ch = fgetc(pf);
printf("%c\n", ch);
//第三次读取:要拿到文件流末尾向前偏移8个单位的一个字符
fseek(pf, -8, SEEK_END);
ch = fgetc(pf);
printf("%c\n", ch);
fclose(pf);
pf = NULL;
return 0;
}
ftell函数():
- 该函数可以返回文件指针相对于起始位置的偏移量;
- long int ftell ( FILE * stream );
rewind()函数:
- 让文件指针回到文件初始位置;
- void rewind ( FILE * stream );
二进制文件和文本文件
我们知道数据在内存中是以二进制形式存储的,对于文件而言:如果不加转换直接输出到外存就是二进制文件;如果要在外存上以ASCII码形式存储,就需要提前转换最后以ASCII码值形式存储的文件就是文本文件。
对于字符,一律使用ASCII码形式存储,但对于数值型数据,即可以使用ASCII码存储也可以使用二进制形式存储。
由此可见:对于10000在数,如果以二进制形式存储占用4个字节,如果以ASCII码存储占用5个字节。试想:那对于数字1呢?
显而易见,二进制文件存储和文本文件存储对不同范围的数字可以做到节省空间
对二进制文件深入理解:
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "wb");
int a = 10000;
if (pf != NULL)
{
fwrite(&a, 4, 1, pf);
fclose(pf);
pf = NULL;
}
return 0;
}
对于上面这段代码,我们知道是将数值10000放入了test.txt文件中,但我们无法直接看到它在文件中的真实值,于是使用vs的二进制编辑器即可查看:
文件读取结束判定
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen is failed !");
return;
}
int c = 0;
//由于要检查EOF——EOF本质是0——所以是int
while (c = fgetc(pf) != EOF)
{
putchar(c);
}
//直到while不执行了—读取结束了—判断是什么原因结束的
if (ferror(pf))
{
printf("读取中出现错误\n");
}
else if (feof(pf))
{
printf("读取到文件尾\n");
}
fclose(pf);
pf = NULL;
return 0;
}
二进制文件的判断:
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf = fopen("test.txt", "rb");
int arr[5] = { 0 };
if (pf == NULL)
{
return;
}
size_t num = fread(arr, sizeof(int), 5, pf);
if (num == 5)
{
//说明全部读取成功
printf("Array read successfully\n");
}
else
{
//说明读取不够指定长度—判断是什么原因
if (ferror(pf))
{
printf("读取中出现错误\n");
}
else if (feof(pf))
{
printf("读取到文件尾\n");
}
}
fclose(pf);
pf = NULL;
return 0;
}