用户在应用开发过程中会经常需要访问文件。Linux下读写文件的方式有两大类:标准I/O和文件I/O。
一.Linux标准I/O
标准I/O:ANSI C中定义的用于I/O操作的一系列函数。
只要操作系统安装了C库,标准I/O就可以调用,源代码无需修改,就可以在其它操作系统下编译,具有很好的可移植性。
使用标准I/O可以减少系统调用的次数,提高系统效率。
标准I/O执行时会用到系统调用。为了避免频繁地执行系统调用会增加系统的开销的产生,标准I/O使用时在用户空间创建缓冲区,读写时先操作缓冲区,合适时机再系统调用。
(1)系统调用
操作系统负责管理和分配所有的计算机资源,为了更好地服务与应用程序,操作系统提供了一组特殊接口—系统调用。通过系统接口,用户可以使用操作系统内核提供的各种功能,如分配内存、创建进程、实现进程之间的通信。
不同操作系统提供的系统调用的接口各不相同,Linux系统调用接口继承UNIX系统调用最有用的部分。在执行系统调用时,Linux必须从用户态切换到内核态,处理相应请求,然后再返回用户态。系统调用按功能可以分为进程控制、存储管理、网咯管理、文件系统、套接字控制、用户管理。
(2)用户程序编程接口
利用系统调用接口程序可以访问各种资源,但实际开发程序并不直接使用系统调用接口,而是直接使用用户程序编程接口(API)。
API:各种库函数(C库最重要)
在Linux中,API遵循UNIX的POSIX标准。
为什么不直接使用系统调用接口?
1)系统调用接口功能简单,无法满足程序的 需求
2)不同操作系统的系统调用接口不兼容,程序移植工作量大
3)API是程序,它具有良好的可移植性
二.标准I/O编程
(1)流的定义
标准I/O的对象就是流。当用标准I/O打开一个文件时,就会创建一个FILE结构体描述该文件。其中FILE结构体称为流。标准I/O函数都基于流进行各种操作。
标准I/O中的缓冲类型
缓冲类型 | 说明 |
---|---|
全缓冲 | 当填满标准I/O缓冲区后才进行实际I/O操作。对于存放在磁盘上的普通文件,用标准I/O打开时默认是全缓冲。当缓冲区已满或执行flash操作时才进行磁盘操作 |
行缓冲 | 当输入输出中遇到换行符时执行I/O操作,标准输入流和标准输出流是行缓冲的例子。 |
无缓冲 | 不对I/O进行缓冲,即在对流的读写时会立即操作实际的文件。标准出错流是不带缓冲的,这就使得出错信息可以立即显示在终端上,而不管输出内容是否有换行符。 |
(2)流的打开
使用标准I/O打开文件的函数有fopen()、fdopen()和freopen()。
fopen():可以指定打开文件的路径和模式
fdopen():可以指定打开的文件描述符和模式
freopen():除可指定打开的文件和模式外,还可指定特定的I/O流
#include<stdio.h>
FILE * fopen(const char * path,const char * mode)
path:包含要打开的文件路径及文件名
mode:文件打开方式
函数返回值:成功指向FILE的指针,失败为NULL
mode取值 | 说明 |
---|---|
r或rb | 打开只读文件,该文件必须存在 |
r+或r+b | 打开可读写的文件,该文件必须存在 |
w或wb | 打开只写文件,若存在则文件长度为0;若不存在则新建 |
w+或w+b | 打开可读写文件,若文件存在则文件长度为0;若不存在则新建 |
a或ab | 以附加的方式打开只写文件,若文件存在则写入数据被加入文件尾;若文件不存在则新建 |
a+或a+b | 以附加方式打开可读写的文件,若文件存在则写入数据被加入文件尾;若文件不存在则新建 |
#include<stdio.h>
int main(int argc, char *argv[]){FILE *fp;if((fp=fopen("test.txt","w+"))==NULL){printf("fopen error\n");return -1;}return 0;}
在每一个选项中加入b字符用来告诉函数库打开的文件为二进制文件,而非纯文本文件。当用户程序运行时,系统会自动打开3个流:stdin(标准输入流)、stdout(标准输出流)、stderr(标准错误流)
(3)流的关闭与错误处理
关闭流的函数为fclose(),该函数将流的缓冲区的数据全部写入文件中,并释放相关资源。
#include<stdio.h>
int fclose(FILE * stream);
stream:已打开的流指针
函数返回值,成功为0,失败为EOF;
程序结束会关闭所有流。
标准I/O函数执行时如果出现错误,会把错误码保存在全局变量errno中。程序员可以通过相应的函数打印错误信息,错误处理的相关函数perror(),strerror();
#include<stdio.h>
void perror(const char*s);
s:在标准错误流上输出的信息
返回值:无
#include<stdio.h>
int main(int argc, char *argv[]){FILE *fp;if((fp=fopen("test.txt","w+"))==NULL){perror("fopen");return -1;}return 0;}
fopen:NO such file or directory
#include<string.h>
#include<errno.h>
char *strerror(int errnum);
errnum:错误码
函数返回值:错误码对应的错误信息
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main(int argc, char *argv[]){FILE *fp;if((fp=fopen("test.txt","w+"))==NULL){printf("fopen:%s\n",strerror(errno));