目录
前言:
本篇重点对于文件打卡和关闭 及 输入输出函数、随机读写函数进行学习和理解 。
关于文件的概念系列知识不再详述。
对于输入输出 切记是站在程序的角度来说的。程序输出数据或程序输入数据
随机读取实际上是切换指针的位置
文件打开和关闭:
打开函数 fopen
FILE* fopen(const char* filename, const char* mode) //(文件名。打开方式)
关闭函数 fclose
int fclose(FILE* stream) //(文件指针)
int main()
{
FILE* pf = fopen("test.txt", "r");
//打开文件
if (pf == NULL)
{
perror("fopen:");
return;
}
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
打开函数fopen 的第一个参数是要打开的文件名 ,第二个参数是打开方式
其中常用的打开方式有 "r"、"w"、"a"、"rb"、"wb"....
若不能成功打开,返回空指针,因此我们需要对返回值进行判断,若为空指针必须提前结束。
关闭函数fclose 的参数是文件指针。
不能是空指针。
输入输出函数:
我们在开始之前 再次重申
对于输入输出 切记是站在程序的角度来说的。程序输出数据或程序输入数据
其次再说一下流,流是什么?我不知道。我知道什么?
我想写程序到硬盘、到文件、到屏幕。。。但是怎么写进去我不知道
我们抽象有一个流在我和外部设备之间,我只是一个什么不懂的程序员,所以我把数据写到流中,再让流写入这些外部设备,流是怎么实现的呢,我也不知道。
我还知道什么?
只要一个C程序运行 这三个标准xx流 是默认打开的
标准输入流 stdin //键盘
标准输出流 stdout //屏幕上
标准错误流 stderr //屏幕
ok 足够了 让我们开始下面的学习:
fpuc - 把字符写入文件中
适用所有输出流
int fputc(int character, FILE * stream);
int main()
{
//打开文件
FILE* pf = fopen("test.txt","w");//写入方式
if(pf == NULL)
{
perror("fopen");
return ;
}
//写入文件,程序输出
fputc('c',pf);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fgetc - 从文件中读取字符
适用所有输入流
int fgetc ( FILE * stream );
int main()
{
//打开文件
FILE* pf = fopen("test.txt","r");//只读方式
if(pf == NULL)
{
perror("fopen");
return ;
}
//读取文件,程序输入
char c = fgetc(pf);//创建变量接收
printf("%c",c);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fputs - 写入字符串到文件中
适用所有输出流
int fputs ( const char * str, FILE * stream )
int main()
{
//打开文件
FILE* pf = fopen("test.txt","w");//写入方式
if(pf == NULL)
{
perror("fopen");
return ;
}
//写入文件 程序输出
fputs("abc\n",pf);//字符串中有\n 才会换行
fputs("def",pf);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fgets - 从文件中读取字符串
适用所有输入流
char * fgets ( char * str, int num, FILE * stream );
int main()
{
//打开文件
FILE* pf = fopen("test.txt","r");//只读方式
if(pf == NULL)
{
perror("fopen");
return ;
}
//读取文件,程序输入
char c[256] = {0};
fgets(c,256,pf);//第二个参数实际读取的是n-1
printf("%s",c);
fgets(c,256,pf);//读取下一行
printf("%s",c);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fprintf - 格式化写入文件
适用所有输出流
int fprintf(FILE* stream, const char* format, ...);
看不懂?简单,再看一下printf
int printf ( const char * format, ... );发现就多出来一个流 pf
struct S
{
char name[20];
int age ;
double d;
};
int main()
{
struct S s={"张三",20,95.5};
//打开文件
FILE* pf = fopen("test.txt","w");//写入方式
if(pf == NULL)
{
perror("fopen");
return ;
}
//写入文件 程序输出
fprintf(pf,"%s %d %lf",s.name,s.age,s.d);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fscanf - 从文件中读取格式化数据
适用所有输入流
int fscanf ( FILE * stream, const char * format, ... );
struct S
{
char name[20];
int age ;
double d;
};
int main()
{
struct S s={0};
//打开文件
FILE* pf = fopen("test.txt","r");//只读方式
if(pf == NULL)
{
perror("fopen");
return ;
}
//读取文件 程序输入
fscanf(pf,"%s %d %lf",s.name,&s.age,&s.d);
printf("%s %d %lf",s.name,s.age,s.d);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fwrite - 二进制写入文件
适用于文件
size_t fwrite(const void* ptr, size_t size, size_t count, FILE* stream);
struct S
{
char name[20];
int age ;
double d;
};
int main()
{
struct S s={"张三",20,95.5};
//打开文件
FILE* pf = fopen("test.txt","wb");//二进制 写入方式
if(pf == NULL)
{
perror("fopen");
return ;
}
//写入文件 程序输出
fwrite(&s,sizeof(struct S),1,pf);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fread - 从文件中读取二进制
适用于文件
size_t fread(void* ptr, size_t size, size_t count, FILE* stream);
struct S
{
char name[20];
int age ;
double d;
};
int main()
{
struct S s={0};
//打开文件
FILE* pf = fopen("test.txt","rb");//二进制 读方式
if(pf == NULL)
{
perror("fopen");
return ;
}
//读取文件 程序输入
fread(&s,sizeof(struct S),1,pf);
printf("%s %d %lf",s.name,s.age,s.d);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
随机读写
本质上是切换指针的位置 ,下面的函数都是为切换指针服务的
本次三个函数我们综合一个例子上一起看, 方便理解
fseek - 将指针切到某位
int fseek(FILE* stream, long int offset, int origin);
(流 , 偏移量(相对于起始位置),位置);
其中origin有三个选项, SEEK_CUR 当前位置 、SEEK_SET 起始位置 、SEEK_END 末尾位置
ftell - 计算偏移量
long int ftell(FILE* stream);
rewind - 切回起始位置
void rewind(FILE* stream);
int main()
{
FILE* pf = fopen("test.txt", "r");
if(pf ==NULL)
{
perror("fopen");
return;
}
//读文件
int ch = fgetc(pf);
printf("%c ", ch);//a
ch = fgetc(pf);
printf("%c ", ch);//b
fseek(pf, 2, SEEK_CUR);
ch = fgetc(pf);//e
printf("%c ", ch);
fseek(pf, -5, SEEK_CUR);
ch = fgetc(pf);//a
printf("%c ", ch);
long pos = ftell(pf);
printf("%ld ", pos);//1
rewind(pf);//回到起始位置
pos = ftell(pf);
printf("%ld ", pos);//0
fclose(pf);
pf = NULL;
return 0;
}
文本文件和二进制文件
根据数据存储方式,分为文本文件 和 二进制文件。
文本文件在内存中以二进制存储,然后转到外存前转成ASCII码值的形式
二进制文件则一直使用二进制的方式存储
文件读取结束的判定
谨记 feof函数是在读取结束后 判断是读取失败结束还是读到文件尾结束 。而非判断是否结束
判断文件结束:
文本文件:看返回值是EOF或NULL判断
如fgetc返回EOF;fgets返回NULL
二进制文件:根据返回值是否小于实际要读取的个数判断
文件缓冲区
从内存向磁盘输出数据,不会直接输送,会先输送到内存的缓冲区 然后如果缓冲区满了再一起输送。
同理,从磁盘输入数据,先读取数据,会先到缓冲区,然后缓冲区满了再逐个送到程序数据区
缓冲区的大小是根据C编译系统决定的。
这里有一个例子,我们看一下。
#include <stdio.h>
#include <windows.h>
//VS2013 WIN10环境测试
int main()
{
FILE*pf = fopen("test.txt", "w");
fputs("abcdef", pf);//先将代码放在输出缓冲区
printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
Sleep(10000);
printf("刷新缓冲区\n");
fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
//注:fflush 在高版本的VS上不能使用了
printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
Sleep(10000);
fclose(pf);
//注:fclose在关闭文件的时候,也会刷新缓冲区
pf = NULL;
return 0;
值得注意的是 在fclose关闭文件时,也会刷新缓冲区。
因此我们大概了解,对于文件操作,我们要通过刷新缓冲区,或者在文件操作结束时关闭文件