C语言文件操作
用户级文件操作
C语言
的文件操作也是用户级的文件操作,通过FILE
对象来管理每一个被打开的文件
,以及提供了用户级文件缓冲区,因此还涉及到冲刷缓冲区等问题
FILE
类
FILE
类描述了一个文件流。里面存储了文件控制所需的信息:
- 指向自身缓冲区的的
指针
- 位置指示器
- 状态指示器
所以C语言
中对文件的管理就是对FILE
对象的管理
基础操作 - 针对一般文件
基础示例
1 |
|
以上代码创建了一个file.txt
文件,输入格式化字符串
(就和使用printf打印一样)。然后用flcose
关闭文件流
fopen 打开文件
fopen
能够打开以各种模式
磁盘上的文件
FILE* fopen( const char * filename, const char * mode );
返回值:
- 成功时,返回一个不为空的
FILE*
指针,用于控制该文件 - 失败时,返回
NULL
空指针并设置了全局变量errno
常见模式
| 模式 | 简述 |
| === | === |
| "w"
| 创建一个新的空文件用于输出操作。如果已存在同名文件
,清除原文件并当作新文件处理 |
| "r"
| 只读模式打开文件。且该文件必须存在 |
| "a"
| 打开已有文件时,仅用于在文件末尾追加
新的内容。并且重定位函数(fseek,fsetpos,reweind)
会被忽略,即使成功调用,也没有效果;当文件不存在时,会创建一个新的空文件 |
| “r+
“ | 读写模式打开已有文件,不会清除原文件内容,并且读写时均从文件开头开始。打开后第一次操作为写入时,从文件头部开始逐字符覆盖原文件。注读写模式同时只能读
或写
的一种,第一次取决于先进行哪种操作,可以用fseek
函数转换读写模式 |
| “w+
“ | 读写模式打开新文件,若存在,则清除原文件内容;读写模式的切换和"r+"
模式相同,唯一的区别就是打开时是否清除原文件内容 |
| “a+
“ | 从文件末尾打开读写模式,不会清除原文件内容,若打开后第一次操作为写,则从文件末尾开始;若第一次操作为读,则从头开始;读写模式的切换同上 |
二进制模式
如果要以二进制模式打开文件,只需要在上面的模式末尾加上字符b
若有+
,则b
既可以放在末尾也可以放在中间
r+b
w+b
a+b
rb+
wb+
ab+
强制新建文件
新的C语言标准,C2011
(不是C++11),添加了一种新的说明符w
,可以被添加在任意"w"
后面
"wx"
"wbx"
"w+x"
"w+bx"
/"wb+x"
当文件存在时,w
会强制fopen
函数失败,返回一个NULL
空指针
freopen 重定向文件流
FILE* freopen ( const char *filename, const char *mode, FILE * pFile );
- 如果传入了新的文件名(与
pFile
控制的文件相比),该函数会关闭pFile
原本指向的文件流,并取消关联。然后不论是否成功关闭,freopen
会用和fopen
同样的方式打开该文件 - 如果文件名还是原文件,则只会改变打开模式
返回值:
- 成功时,返回
pFile
内储存的地址 - 失败时,返回
NULL
特别的
freopen
用于进程的输入输出重定向会特别有用
1 | freopen ("outfile.txt","w",stdout);//标准输出重定向到文件 |
重定位 文件流位置指示器(stream position indicator)
文件的抽象内存结构
首先我们要明确一下文件的内存结构,如下图
这里及下文用图中的ptr
代指标题的中的 文件流位置指示器
,这个ptr
决定了每一次对文件的读/写
操作的起点,同时每一次读/写
操作都会使ptr
自动往后走,因此要显示控制ptr
,就得使用fseek,fsetpos
等接口
fseek 重定位
int fseek ( FILE *pFile, long int offset, int origin );
fseek
能过直接重定位ptr
所指的
参数
pFile
:用于控制文件的FILE*
类型指针offset
:则是偏移量,长整型,表示偏移多少字节origin
:该形参标注了偏移量相对于哪个位置计算实际位置
origin
有三个宏可以选
| 宏 | 实际位置 |
| SEEK_SET
| 偏移量从文件头
开始算 |
| SEEK_CUR
| 偏移量从当前文件指针ptr(上文介绍的)所在位置
开始算 |
| SEEK_END
| 偏移量从文件尾
开始算 |
返回值
- 成功时,返回
0
- 失败时,返回
非零值
,同时,这条语句失效,上文说的ptr
没有改变
fgetpos 和 fsetpos 设置 ptr
可以用fgetpos
获取ptr
的当前位置,并使用输出型参数
输出一个fpos_t
类型的变量,而fsetpos
可以用fpos_t
类型的形参设置ptr
的当前位置
就好比ptr
是当前坐标,每次fgetpos
得到一个传送点信息,而fsetpos
就可以用这个传送点信息传送ptr
过去
示例如下
1 |
|
1 | 第2个字符为: e |
fclose 关闭文件流
可以用fclose
显式地关闭文件流
用法为fclose(pFile);
进程正常退出时,也会自动关闭文件流
fprintf 格式化输出字符串
fprintf
能格式化输出字符串到指定文件流,除了要指定文件流,格式化字符串的方式和printf
一样
- 且
fprintf(stdout,format,...)
和printf(format,...)
效果一样
fputs 输出字符串
int fputs ( const char * str, FILE * stream );
fputs
能将C语言
的字符串输入到指定文件流中
fwrite 输出内存数据块
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
ptr
是指向内存数据块
的指针size
是每个数组元素
的大小nmemb
是元素数量stream
是文件流
fwrite可以向指定文件流输入特定大小的内存数据块
1 | int main() |
fscanf 格式化输入
fscanf
能像scanf
读取标准输入流一样,读取指定文件流
- 且
scanf(stdin,format,...)
和printf(format,...)
效果一样
fgets 获取一行
char * fgets (char *str, int num, FILE *stream );
行为
fgets
会一直读取直到换行符
或EOF文件结尾
结束读取,但换行符
作为非法字符不会被拷贝到形参str
中
- 字符串结尾的
\0
会被自动添加,且计算在读入的最大字符数 fgets
和gets
有很大差别,它需要指定最大的读入字符数
形参
str
为传入的字符数组作为缓冲区num
为拷贝的最大字符数,包括自动添加的结尾\0
stream
为指定的文件流
返回值
- 成功时,返回
str
的值 - 失败时,返回
NULL
示例
1 |
|
1 | get | |