打开文件
#include <stdlib.h>
exit(0);//头文件:#include <stdlib.h>
// exit 结束程序,一般0为正常退出,其他数字为异常,其对应的错误可以自己指定
FILE *fopen(文件名,使用方式);
//返回指向指定文件名的文件的指针;
FILE *fp;
fp=fopen("a1.txt","r");
使用文件方式
| 文件使用方式 |
含义 |
如果指定文件不存在 |
| "r"(只读) |
为了输入数据,打开一个已存在的文本文件 |
出错 |
| "w"(只写) |
为了输出数据,打开一个文本文件 |
建立新文件 |
| "a"(追加) |
向文本文件尾追加数据 |
出错 |
| "rb"(只读) |
为了输入数据,打开一个已存在的二进制文件 |
出错 |
| "wb"(只写) |
为了输出数据,打开一个二进制文件 |
建立新文件 |
| "ab"(追加) |
向二进制文件尾追加数据 |
出错 |
| "r+"(读写) |
为了读和写,打开一个文本文件 |
出错 |
| "w+"(读写) |
为了读和写,建立一个新的文本文件 |
建立新文件 |
| "a+"(读写) |
为了读和写,打开一个文本文件 |
出错 |
| "rb+"(读写) |
为了读和写,打开一个二进制文件 |
出错 |
| "wb+"(读写) |
为了读和写,建立一个新的二进制文件 |
建立新文件 |
| "ab+"(读写) |
为了读和写,打开一个二进制文件 |
出错 |
- 用"r"方式:只能用于向计算机输入而不能用作向文件输出数据
- 用"w"方式:只能用于向文件写数据,不能向计算机输入;(若文件不存在,则建立该文件;若文件存在,则先将该文件删除,然后重新建立新文件)
- 用"a"方式:想文件末尾追加新的数据,不删除原有数据;(若文件不存在,则会出错;若文件存在,则打开文件,并将读写位置标记移至文件末尾)
fclose(文件指针);
//关闭文件用close函数;成功关闭返回0,否则返回EOF(-1)
fclose(fp);
- 向文件写数据时,首先将数据输出到缓冲区,待缓冲区中充满后才正式输出给文件,如果数据未填满缓冲区而结束运行,就有可能使缓冲区中的数据丢失。
- fclose函数:用fclose函数关闭文件,先把缓冲区中数据输出到磁盘文件,然后才撤销文件信息区
以字符形式读写
读写一个字符的函数
| 函数名 |
调用形式 |
功能 |
返回值 |
| fgetc |
fgetc(fp) |
从fp指向文件读入一个字符 |
读取成功,带会所读的字符,失败则返回文件结束标记EOF (即-1) |
| fputc |
fputc(ch,fp) |
把字符ch写到文件指针变量fp所指向的文件 |
输入成功,返回值就是输入的字符;输入失败,返回EOF (即-1) |
FILE *fp=fopen("hello.txt",""a+"); //打开文件
char ch=getc(fp);
(ch)!=EOF
/**
*每次读取一个字符,读取到( EOF:宏定义为-1 )结束
*fgetc()和getc的区别:fgetc()为函数实现;为getc()则为宏的实现
*宏避免了方法调用堆栈的操作,但不能传入内联函数(如 i++操作,可能使用之后得出错误结果)
*/
putc(ch,fp);
//写入文件一个字符 ( fputc()/putc()的关系与fgetc()/getc()一样 )
fclose(fp);//关闭文件
以字符串形式读写
char * fgets(char *str,int n,FILE *fp);//从文件读入一个长度为(n-1)的字符串
int fputs(char *str,FILE *fp);//将str所指向的字符串输出到fp所指向的文件中
fputs("China",fp);
读写一个字符串的函数
| 函数名 |
调用形式 |
功能 |
返回值 |
| fgets |
fgets(str,n,fp) |
从fp指向文件读入一个长度为(n-1)的字符串,存放在字符数组str中 |
成功,返回str地址;否则返回NULL |
| fputs |
fputs(str,fp) |
把str所指向的字符串写到文件指针变量fp所指向的文件中 |
成功,返回0;否则返回非0值 |
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main(){
FILE *fp=fopen("G:\\111\\a.txt","w");
char p[10];
gets(p);
while(strcmp(p,"over")){
puts(p);
fputs(p,fp);
fputs("\n",fp);
gets(p);
}
fclose(fp);
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main(){
FILE *fp=fopen("G:\\111\\a.txt","r");
char p[10];
while(!feof(fp)){
fgets(p,11L,fp);
printf("%s",p);
//若使用puts打印字符串时会自动换行,破坏文件原本格式
}
fclose(fp);
}
格式化读写
- 具体细节和printf函数和scanf函数一样,只是在第一个参数位置加入文件指针
int fprintf( FILE *stream,const char *format,... );
//优势:可以格式化写入,可以带一些变量
//如:fprintf( fp,"%d-%d-%d",year,mon,day );
int fscanf( FILE *stream,const char *format,... );
//优势:可以格式化读取,把读取到的部分内容赋值给一些变量
//如:fscanf( fp,"%d-%d-%d",&year,&mon,&day );
以二进制读写
size_t fwrite( void *ptr,size_t size,size_t nmemb,FILE *stream );
size_t fread( void *ptr,size_t size,size_t nmemb,FILE *stream );
/**
*ptr:指向存放数据的指针,该内存的尺寸是 [size*nmenb] 个字节
*size:指定要读取的每个元素的尺寸,最终尺寸为 [size*nmenb]
*nmemb:指定读取的元素个数
*stream:指定带读取的文件流
*返回值:实际上读到的元素个数;如果该值小于 nmemb,就说明读取到文件末尾或有错误(可以用feof()或ferror()标志判断)
*/
- 打开模式字符串加了 'b',用以上方法可以以二进制形式读写;
- 用专门的二进制读写方法:这样就直接可以写入类型数据了;例如:整性数据、浮点型数据、结构体
typedef struct {char name[20];double score;} Student;
void main(){
FILE *fp=fopen("G:\\111\\a.txt","wb");
Student stu[2]={"zhangshan",94,"lisi",96};
int z;
z=fwrite(stu,sizeof(Student),2,fp);
printf("写入%d个数据\n",z);
fclose(fp);
}
- 读取案例:读取时,存放数据的指针必须指向有效地址,否则读取可能出错
typedef struct {char name[20];double score;} Student;
void main(){
FILE *fp=fopen("G:\\111\\a.txt","rb");
Student stu[2],*s=stu;
int z;
z=fread(s,sizeof(Student),2,fp);
printf("读出入%d个数据\n",z);
for(;z>0;z--){
printf("%s:%.2f\n",stu[z-1].name,stu[z-1].score);
}
fclose(fp);
}
随机读写
- 通过修改打开文件的位置指示器来达到直接读取目标位置的方法
- 要注意将指示器位置移动至文件中间再写入数据时,会覆盖相应数据
long int ftell( FILE *stream );
/**
*得到位置指示器的值;编译器认为文件的内容是一个字符数组
*返回值:long 类型的值,返回值即为当前位置字符的下标
*/
rewint( FILE *stream );
/**
*将位置指示器初始化到文件头位置
*写入一些数据后,用该方法回到文件头位置继续写入会覆盖原有内容相应字节的内容
*/
int fseek( FILE *stream,long int offsef,int whence );
/**
*用于设置文件流的位置指示器的位置
*stream:指定代操作的文件流
*offsef:指定从 whence 参数的位置器移动多少个字节(正数向后移动,负数向前移动)
*whence:指定开始移动位置;可以用:
* 0(SEEK_SET)【文件头】
* 1(SEEK_CUR)【 当前的读写位置 】
* 2(SEEK_END)【 文件末尾 】
*返回值:成功返回0;失败返回非0值;如:fseek( fp,sizeof(student Stu)*1,0 );
*/
文件中的指示器
- feof (fp):判断文件指示器位置是否在文件末尾
- ferror (fp):判断文件指针是否发生错误
- clearerr (fp):使文件错误标志和文件结束标志置为0
int feof( FILE *stream );
//位置指示器,读到文件末尾时返回非0值
int ferror( FILE *stream );
//错误指示器,文件读写发生错误时返回非0值(判断是否发生了错误)
clearerr( FILE *stream );
//同时清除位置指示器和错误指示器的状态
程序执行时会打开3个面向终端的标准流
stdin; //标准输入(scanf函数接收数据)
stdout; //标准输出(printf函数打印字符串)
sederr; //标准错误输出(自动打印报错信息)
//重定向:由于标准输出流和标准错误输出流都是直接将信息打印在终端;所以 Linux 可以通过重定向的方法将3个流的信息重定向到一个文件中
//从定向标准输入:< 从定向标准输出:> 从定向标准错误输出:2>例如:
gcc test1.c && ./a.out //(编译text1.c文件)
./a.out 2> error.txt //(执行a.out,并将错误输出流重定向到 error.txt 中)
./a.out > output.txt //(执行a.out,并将输出流重定向到 output.txt 中)
./a.out > 1.txt 2> 2.tet
IO缓冲区:(刷新缓冲区)
- fflush( FILE *stream );手动将文件指针缓冲区的数据刷新入文件中
- 缓冲区自动刷新
- 按块缓存:填满缓冲区后才进行实际的设备读写操作
- 按行缓存:接收到换行符之前,数据都是先缓存在缓冲区中的
- 不缓存:直接读写设备上的数据
int setvbuf( FILE *stream,char *buf,int mode,size_t size );
/**
*设置缓存模式
*stream:指定打开的数据流;
*buf:传入字符数组,指定分配的缓冲区(为NULL时,函数会自动分配一个指定尺寸的缓冲区)
*size:指定缓冲区的尺寸( 字节 );
*mode:缓冲区模式
* _IOFBF(按块缓存)
* _IOLBF(按行缓存)
* _IONBF(不缓存)
*返回值:调用成功返回0;调用失败返回非0值
*/