C语言
- 知识基础
- 控制语句
- 函数
- 输入输出
- 指针和数组
- 用户自定义数据类型
- 文件操作
结合《输入输出》理解文件流和缓存区的概念!
一、打开与关闭文件
1.文件指针
每个被使用的文件都会在内存中开辟一个文件信息区,存储与文件相关的信息,这些信息被存在一个结构体变量中,名为FILE
结构体,我们想要进行文件操作实际上不会直接操作磁盘,而是通过库函数读入文件信息,让函数进行相应的操作实现我们的需求。
一般我们会定义一个指针指向打开的文件信息区,文件指针:FILE *fp
,我们在输入输出中已经提到过标准输入输出的文件指针为stdin\stdout
,我们可以简单的将文件指针看作文件流的等价物。
#ifndef _FILE_DEFINED
struct _iobuf {
char *_ptr; //文件输入的下一个位置
int _cnt; //当前缓冲区的相对位置
char *_base; //指基础位置(即是文件的起始位置)
int _flag; //文件标志
int _file; //文件的有效性验证
int _charbuf; //检查缓冲区状况,如果无缓冲区则不读取
int _bufsiz; //
char *_tmpfname; //临时文件名
};
typedef struct _iobuf FILE;
#define _FILE_DEFINED
#endif
综上,我们熟练掌握文件操作函数,就啥毛病没有。。。
2.打开文件
函数声明FILE *fopen(const char *filename, const char *mode)
输入:文件名(文件路径+文件主干+文件后缀),存储在数组中是有长度限制的;
访问模式参数,描述的是文件打开的方式,允许的操作等状态。
访问模式 | 说明 |
---|---|
r | 只读,可以向程序输入文件中的数据,如果文件不存在,报错 |
w | 只写,程序向文件写入数据,如果文件不存在,新建一个文件 |
a | 追加,程序从文件末尾写入数据,如果文件不存在,出错 |
r+/a+ | 读写,文件不存在,报错 |
w+ | 读写,文件不存在,新建文件 |
*b* | 打开二进制文件 |
返回值:返回一个文件指针,指向打开的文件流,所以必须要用一个文件指针变量接收返回值;如果出错,返回NULL ,可以据此判断出错与否。 | |
说明:主要掌握w 、r 、a 就行;a 模式会保留文件末尾的文件结束符EOF ,a+ 模式则不会;规范化打开文件,判断成功与否; |
FILE fp;
if((fp=fopen(filename, "r")) == NULL){//还有多种判断方式
printf("cann't open %s\n", filename);
exit(0);
}
函数声明FILE *freopen(const char *filename, const char *mode, FILE *stream)
输入:新文件名;访问模式;旧文件流指针,该指针对应一个已经打开的文件流;
返回值:关闭旧的文件流,依规定的访问方式打开文件名对应文件,返回新的文件指针;如果失败,返回NULL
;
说明:本函数可以用于重定向,比如改变标准输出至新的文件,输入的内容将写进指定文件而非显示器;
#include <stdio.h>
int main (){
FILE *fp;
printf("该文本重定向到 stdout\n");
fp = freopen("file.txt", "w+", stdout);
printf("该文本重定向到 file.txt\n");
fclose(fp);
return 0;
}
3.关闭文件和文件控制函数
函数原型int fclose(FILE *stream)
输入:文件指针,代表想要关闭的文件流。
返回值:整数,正常关闭返回零;出错返回EOF
。
说明:一个open对应一个close,这是基本操作;close会刷新缓冲区。
函数原型void clearerr(FILE *stream)
输入:文件指针,想要清空错误状态的文件流。
返回值:空。
说明:在发生错误的情况之后使用,例如,让open函数返回值不再是EOF
。
函数原型int feof(FILE *stream)
输入:文件指针,一个打开的文件流;
返回值:文件流状态是文件结束符EOF
时,该函数返回一个非零值,否则返回零。
说明:文件到末尾的情况下(读到-1
),状态被置EOF
;需要注意当文件内部位置指针指向文件结束时,并未立即置位 FILE 结构中的文件结束标记,只有再执行一次读文件操作,才会置位结束标志,此后调用 feof 才会返回为真。
函数原型int ferror(FILE *stream)
输入:文件指针。
返回值:整数,标识文件流当前的状态,只要当前文件操作出错,函数返回非零数,如果无错,返回零。
说明:其作用是检查每一次文件流操作之后的错误状态,与feof
不同,文件操作出错,立即置为1。
函数原型int fflush(FILE *stream)
输入:文件指针;
返回值:刷新缓冲区成功返回零;出错返回EOF
;
说明:在文件关闭时,缓冲区会自动刷新,但是在一个循环执行较久的程序中,最好在较小的操作后及时刷新缓冲区,从而及时得到结果,以便之后可能的使用。
二、读写函数
1.文件读写
函数原型size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
输入:ptr
指向将要接受文件内容的内存空间的指针;size
要读取的元素的大小,以字节为单位;nmemb
表示要读取的元素的个数;最后的文件指针指明对象;
返回值:成功读取的元素总数会以 size_t 对象返回,size_t 对象是一个整型数据类型。如果总数与 nmemb 参数不同,则可能发生了一个错误或者到达了文件末尾。
说明:能够读取多少内容,取决于size*nmemb
;
函数原型size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
输入:ptr
指向将要写入文件的内容存储的内存空间的指针;…
返回值:…
说明:和fread
使用方法是一致的!!!二者采用的是二进制读写的方式,效率是高于之后的格式化读写方式的;
函数原型int fprintf(FILE *stream, const char *format, ...)
输入:文件流;格式化标签和之前的标准输入输出是一致的;
返回值:如果成功,则返回写入的字符总数,否则返回一个负数。
2.格式化输入输出(字符输入输出)
- int fprintf(FILE *stream, const char *format, …)
- int sprintf(char *str, const char *format, …)
- int fscanf(FILE *stream, const char *format, …)
- int sscanf(const char *str, const char *format, …)
- int fgetc(FILE *stream)
- char *fgets(char *str, int n, FILE *stream)
- int fputc(int char, FILE *stream)
说明:以上函数使用方式与到标准输入输出的用法大同小异,可以放心使用,其使用注意事项都是一致的。
三、文件定位
函数原型int fseek(FILE *stream, long int offset, int whence)
输入:文件流;这是相对 whence 的偏移量,以字节为单位;开始添加偏移 offset 的位置;
常量 | 含义 |
---|---|
SEEK_SET | 文件开头 |
SEEK_CUR | 当前位置 |
SEEK_END | 文件末尾 |
返回值:如果成功,则返回零,否则返回一个非零数。
说明:可以实现比较自由的定位;
函数原型void rewind(FILE *stream)
输入:文件流;
返回值:空;
说明:将指定文件流指回文件开头;
总结
文件是系统对磁盘数据的抽象,对文件的读写通过简单的函数调用就可以实现,我们要熟悉文件流的概念,掌握打开->操作->关闭
三步走,熟悉读写函数的参数和作用保证万事大吉!