读写模式
FILE 结构体
三种刷新缓冲区的操作
简单读写示例: fgetc 与 fputc
fgets 与 fputs
fread 与 fwrite
fscanf 与 fprintf
rewind 和 fseek 随机读写文件
#include <stdio.h>
fclose() 的返回值为0,如果返回非零值则表示有错误发生
- 文本模式和二进制模式的区别
- windows
- windows中fopen函数用文本模式写入文件时,会自动将\n换成\r\n,实现自动换行。
- 用二进制模式时,写入文件的是\n,windows并不能识别到换行,因此出现了小方块。
- linux系统中两种模式就没有区别
- windows
读写模式
模式 | 介绍 |
---|---|
“r”(只读) | 为输入打开一个文本文件 对文件进行读操作 |
“w”(只写) | 为输出打开一个文本文件 对文件进行写操作 |
“a”(追加) | 向文本文件尾添加数据 |
“rb”(只读) | 为输入打开有一个二进制文件 |
“wb”(只写) | 为输出打开一个二进制文件对文件进行写操作 |
“ab”(追加) | 向二进制文件尾添加数据 |
“r+”(读写) | 为读写打开一个文本文件 |
“w+”(读写) | 为读写建立一个新的文本文件 |
“a+”(读写) | 向文本文件尾添加数据 |
“rb+”(读写) | 为读写打开一个二进制文件 |
“wb+”(读写) | 为读写建立一个新的二进制文件 |
“ab+”(读写) | 为读写打开一个进制文件 |
"t" | 文本文件,如果不写默认"t" |
- 调用 fopen() 函数时必须指明读写权限,但是可以不指明读写方式(此时默认为"t")。
- 读写权限和读写方式可以组合使用,但是必须将读写方式放在读写权限的中间或者尾部(换句话说,不能将读写方式放在读写权限的开头)。例如:
- 将读写方式放在读写权限的末尾:"rb"、"wt"、"ab"、"r+b"、"w+t"、"a+t"
- 将读写方式放在读写权限的中间:"rb+"、"wt+"、"ab+"
FILE 结构体
struct _iobuf {
char *_ptr; // 下一个要被读取的字符地址
int _cnt; // 剩余的字符,如果是输入缓冲区,那就表示缓冲区中还有多少个字符未被读取
char *_base; // 缓冲区基地址
int _flag; // 读写状态标志位
int _file; // 文件描述符
int _charbuf;
int _bufsiz; // 缓冲区大小
char *_tmpfname;
};
typedef struct _iobuf FILE;
三种刷新缓冲区的操作
- fclose
- fflush(fp)
- 写满
简单读写示例
#include <iostream>
#include <error.h>
int main()
{
FILE *fp;
char c,ret;
fp=fopen("1.txt","r+");
if(NULL == fp)
{
perror("fopen");
goto error;
}
/*
// 操作成功返回 该字符,操作失败(已经读到了文件文件末尾) 返回 “EOF”
while((c = fgetc(fp)) != EOF){
putchar(c);
}
*/
c='H';
// 运行成功返回该字符,运行失败,返回 EOF(-1)
ret=fputc(c,fp);
if(EOF != ret)
{
perror("fputc");
goto error;
}
fclose(fp);
error:
return 0;
}
fgets 与 fputs
只能读字符串,不能读取整型数据,或者结构体类型的
-
函数原型 int fputs(const char *s, FILE *stream);
- 写入成功返回非负数,失败返回 EOF
-
函数原型 char *fgets(char *s, int n, FILE *stream)
- 读取成功时返回字符数组首地址,也即 str;读取失败时返回 NULL
- 如果开始读取时文件内部指针已经指向了文件末尾,那么将读取不到任何字符,也返回 NULL
- 读取到的字符串会在末尾自动添加 '\0'
fgets() 遇到换行时,会将换行符一并读取到当前字符串.
gets() 不一样,它会忽略换行符.
fread 与 fwrite
- 函数原型 size_t fread ( void *ptr, size_t size, size_t count, FILE *fp );
- 函数原型 size_t fwrite ( void * ptr, size_t size, size_t count, FILE *fp );
- ptr 为内存区块的指针,它可以是数组、变量、结构体等。
- fread() 中的 ptr 用来存放读取到的数据
- fwrite() 中的 ptr 用来存放要写入的数据。
- size:表示每个数据块的字节数。
- count:表示要读写的数据块的块数。
- fp:表示文件指针。
- 理论上,每次读写 size*count 个字节的数据。
- 对于 fwrite() 来说,肯定发生了写入错误,可以用 ferror() 函数检测。
- 对于 fread() 来说,可能读到了文件末尾,可能发生了错误,可以用 ferror() 或 feof() 检测。
- ptr 为内存区块的指针,它可以是数组、变量、结构体等。
示例
#define N 2
struct stu{
char name[10];
int num;
int age;
float score;
}boya_t[N],boyb_t[N],*pa,*pb;
void work4()
{
FILE *fp;
pa = boya_t;
pb = boyb_t;
int i;
if((fp=fopen("1.txt","wb+")) == NULL)
{
perror("fopen");
goto err;
}
printf("Input data:\n");
for (i=0;i<N;++i,pa++)
{
scanf("%s %d %d %f",pa->name,&pa->num,&pa->age,&pa->score);
}
fwrite(boya_t,sizeof(struct stu),N,fp);
rewind(fp);
fread(boyb_t,sizeof(struct stu),N,fp);
for (i=0;i<N;++i,pb++)
{
printf("%s %d %d %5.2f\n",pb->name,pb->num,pb->age,pb->score);
}
fclose(fp);
err:
return;
}
void work5()
{
FILE *fp;
int i;
pb = boyb_t;
if((fp=fopen("1.txt","rb+")) == NULL)
{
perror("fopen");
goto err;
}
fread(boyb_t,sizeof(struct stu),N,fp);
for (i=0;i<N;++i,pb++)
{
printf("%s %d %d %5.2f\n",pb->name,pb->num,pb->age,pb->score);
}
fclose(fp);
err:
return;
}
int main()
{
work5();
return 0;
}
fscanf 与 fprintf
- fscanf() 和 fprintf() 和前面使用的 scanf() 和 printf() ,功能相似都是格式化读写函数
- 区别fscanf 和 fprintf 的读写对象不是键盘和显示器, 而是磁盘文件
- 函数原型 int fscanf ( FILE *fp, char * format, ... );
- 函数原型 int fprintf ( FILE *fp, char * format, ... );
- fprintf() 返回成功写入的字符的个数,失败则返回负数.fscanf() 返回参数列表中被成功赋值的参数个数。
示例
void work4()
{
FILE *fp;
int i;
pa = boya_t;
pb = boyb_t;
if((fp = fopen("1.txt","wt+")) == NULL)
{
perror("fopen");
goto err;
}
for (i=0;i<N;++i,pa++)
{
scanf("%s %d %d %f",pa->name,&pa->num,&pa->age,&pa->score);
}
pa = boya_t;
for (i=0;i<N;++i,pa++)
{
// 将boya中的数据写入到文件
fprintf(fp,"%s %d %d %f\n",pa->name,pa->num,pa->age,pa->score);
}
// 重置文件指针
rewind(fp);
// 从文件中读取数据,保存到boyb中
for (i=0;i<N;++i,pb++)
{
fscanf(fp,"%s %d %d %f\n",pb->name,&pb->num,&pb->age,&pb->score);
}
pb=boyb_t;
for (i=0;i<N;++i,pb++)
{
printf("%s %d %d %5.2f\n",pb->name,pb->num,pb->age,pb->score);
}
fclose(fp);
err:
return;
}
rewind 和 fseek 随机读写文件
实现随机读写的关键是要按要求移动位置指针,这称为文件的定位。常用函数有两个 rewind() 和 fseek()。
- 函数原型 void rewind ( FILE *fp );
- 函数原型 int fseek ( FILE *fp, long offset, int origin );
- fp 为文件指针,也就是被移动的文件。
- offset 为偏移量,也就是要移动的字节数。之所以为 long 类型,是希望移动的范围更大,能处理的文件更大。
- offset 为正时,向后移动;offset 为负时,向前移动。
- origin 为起始位置,也就是从何处开始计算偏移量。
- fseek() 一般用于二进制文件
起始点 常量名 常量值 文件开头 SEEK_SET 0 当前位置 SEEK_CUR 1 文件末尾 SEEK_END 2
示例
void work6()
{
FILE *fp;
int i;
pa = boya_t;
if((fp = fopen("1.txt","wb+")) == NULL)
{
perror("fopen");
goto err;
}
printf("Input data:\n");
for (i=0;i<N;++i,pa++)
{
scanf("%s %d %d %f",pa->name,&pa->num,&pa->age,&pa->score);
}
fwrite(boya_t,sizeof(struct stu),N,fp);
fseek(fp,sizeof(struct stu),SEEK_SET);
fread(&boyb_t,sizeof(struct stu),1,fp);
printf("%s %d %d %5.2f\n",boyb_t.name,boyb_t.num,boyb_t.age,boyb_t.score);
fclose(fp);
err:
return;
}