一.文件分类
1.文件:磁盘(硬盘)上的文件
1.
(1)程序文件:源程序文件(后缀.c)目标文件(windows环境后缀.obj)可执行程序(windows环境后缀.exe)
(2)数据文件:程序运行时读写的数据(程序运行需要从中读取数据的文件或输出内容的文件)
2.
(1)二进制文件:数据在内存中以二进制的形式存储
(2)文本文件:以ASCII字符的形式存储的文件
2.文件名:文件路径+文件主干名+文件后缀
二.文件的打开与关闭
1.流:程序的数据需要输出到各种外部设备也需要从外部设备获取数据(方便操作的中间过程)
外部设备----------输入(流)------------->程序----------------输出(流)------------->外部设备
2.标准流:C语言程序启动时默认打开的三个流
stdin:标准输入流,在大多数环境中从键盘输出(scanf)
stdout:标准输出流,在大多数环境中输出至显示器(printf)
stderr:标准错误流,在大多数环境中输出至显示器
这三个流的类型是:FILE*,称文件指针,通过FILE*的文件指针来维护流的各种操作
3.文件指针:每个被使用的文件都在内存中开辟一个相应的文件信息区用以存放文件的相关信息(文件名,状态,文件位置等),保存于一个结构体变量中,该结构体类型由系统声明叫FILE(不同编译器的FILE的内容大同小异)每打开一个文件时,系统自动创建一个FILE结构的变量,并填充其中的信息,由一个FILE指针维护这个FILE结构的变量。
(1)打开文件 (2)产生FILE
data.txt(文件)<-------------------------文件信息区<---------------------------FILE*pf(维护)
可通过pf找到文件信息区(过程为流)
4.文件的打开
(1)文件在读之前先打开文件,在使用结束之后关闭文件
(2)在编写程序时,打开文件的同时会返回一个FILE*的指针变量指向该文件(建立了指针和文件的关系)
(3)fopen函数打开文件,fclose函数关闭文件
FILE*fopen(const char * filenamen (打开文件名) , const char * mode(打开方式));
int fclose (FILE * stream);
(4) 打开方式
“r" 只读 若指定文件不存在直接报错
“w” 只写 若指定文件不存在会新建一文件
“a” 追加 若指定文件不存在会新建一文件
“rb” 二进制只写 若指定文件不存在直接报错
“wb” 二进制只写 若指定文件不存在会新建一文件
“ab” 二进制追加 若指定文件不存在会新建一文件
“r+” 读写 若指定文件不存在直接报错
“w+” 读写 若指定文件不存在会新建一文件
“a+” 读写 若指定文件不存在会新建一文件
“rb+” 二进制读写 若指定文件不存在直接报错
“wb+” 二进制读写 若指定文件不存在会新建一个文件
“ab+” 二进制读写 若指定文件不存在会新建一个文件
例:
int main()
{
FILE* pf = fopen("data.txt", "w");
if(pf==NULL)
{
perroe("fopen");
return 1;
}
fclose(pf);
pf = NULL;
return 0;
}
三.读写方式
1.顺序输入
函数名 | 功能 | 适用范围 |
fgetc | 字符输入函数 | 所有输入流 |
fputc | 字符输出函数 | 所有输出流 |
fgets | 文本行输入函数 | 所有输入流 |
fputs | 文本行输出函数 | 所有输出流 |
fscanf | 格式化输入函数 | 所有输入流 |
fprintf | 格式化输出函数 | 所有输出流 |
fread | 二进制输入 | 所有输入流 |
fwrite | 二进制输出 | 所有输出流 |
(1)fgetc函数:
int fgetc ( FILE * stream(位置) );
(2)fputc函数:
int fputc ( int character(内容), FILE * stream(位置) );
(3)fgets函数
char * fgets (char * str(读入的数据), int num(最多读取个数), FILE * stream(读取的流) );
(4)fputs函数
int fputs ( const char * str, FILE * stream );
(5)fscanf函数
int fscanf ( FILE * stream, const char * format, ... );
(6)fprintf函数
int fprintf ( FILE * stream, const char * format, ... );
(7)fread函数
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
(8)fwrite函数
size_t fwrite ( const void * ptr(写入的起始位置), size_t size(写入元素的大小(字节)), size_t count(元素个数), FILE * stream (流));
(9)函数类比
scanf-----针对标准输入(键盘)的格式化输入函数
printf-----针对标准输出(屏幕)的格式化的输出函数
fscanf----针对所有输入流的格式化输入函数
fprintf-----针对所有输出流的格式化输出函数
sscanf-----在字符串中读取一个格式化的数据
sprintf------把格式化的数据转换成字符串
struct S
{
char name[20];
int age;
float score;
};
int main()
{
struct S s = { "zhangsan",20,90.5 };
char arr[100] = { 0 };
sprintf(arr, "%s %d %f", s.name, s.age, s.score);
printf("%s", arr);
return 0;
}
2.随机读写
(1)定义:根据文件指针的位置和偏移量来定位文件指针(未见内容的光标)
(2)函数:fseek:
int fseek ( FILE * stream(流), long int offset(偏移量), int origin(起始位置) );
origin:SEEK_SET 从起始位置开始的偏移量
SEEK_CUR 从当前位置开始的偏移量
SEEK_END 从末尾位置开始的偏移量
例:找到末尾位置向前便宜6位的内容并打印
fseek(pf, -6, SEEK_END);
ch = fgetc(pf);
printf("%c\n", ch);
(3)ftell:返回文件指针相对于起始位置的偏移量(可用来计算文件字节大小)
long int ftell( FILE * stream );
(4)rewind:让文件指针的位置返回到文件的起始位置
void rewind ( FILE * stream );
四.文件读取结束的判定
1.feof-----在文件读取结束后判断是否是因为遇到文件末尾而结束
2.ferroe--在文件读取结束后判断是否是因为遇到错误而结束
3.文件读取结束判断:fgetc返回值是否位EOF,fgets的返回值是否位NULL
4.二进制文件结束判断:判断返回值是否小于实际要读的个数(使用函数fread)
fread:
size_t fread(真实读取个数) ( void * ptr(放入的地址), size_t size, size_t count(想读的个数), FILE * stream (流));
#include<stdio.h>
enum { SIZE = 5 };
int main(void)
{
double a[SIZE] = { 1.,2.,3.,4.,5. };
FILE* fp = fopen("test.bin", "wb");
fwrite(a, sizeof * a, SIZE, fp);
fclose(fp);
double b[SIZE];
fp = fopen("test.bin", "rb");
size_t ret_code = fread(b, sizeof * b, SIZE, fp);
if (ret_code == SIZE)
{
puts("Array read successfully,contents:");
for (int n = 0; n < SIZE; ++n)
{
printf("%f", b[n]);
putchar('\n');
}
}
else
{
if (feof(fp))
printf("Error reading test,bin:unexpected end of file\n");
else if (ferror(fp))
{
perror("Error reading test.bin");
}
}
fclose(fp);
return 0;
}
5.文件缓冲区
程序数据会先经过文件缓冲区再存入硬盘,同时从硬盘中取出数据也要经过文件缓冲区,因为文件缓冲区的存在,C语言在操作文件的时候需要刷新缓冲区或在文件操作结束的时候关闭文件(否则可能会导致文件丢失)
刷新函数: fflush ( pf ) 关闭函数: fclose ( pf )