基本概念
输入:数据从内核空间流向用户空间,站在用户空间的角度来看就是将数据从内核空间读到用户空间,属于读操作,例如库函数scanf;
输出:数据从用户空间流向内核空间,站在用户空间的角度来看就是将数据从用户空间写到内核空间,属于写操作,例如库函数printf。
标准IO
特性:
1、标准C库函数
2、属于高级IO,移植性和通用性较强
3、自带缓存,用于临时存放数据,以减少操作磁盘的次数,保护硬件
4、通过文件流操作IO
注:文件流本质上是结构体指针,指向struct _IO_FILE类型的结构体;此外标准IO也是基于文件IO来实现的。
linux自带3个标准流
标准输入 stdin
使用全缓存,4k大小,其刷新条件是
1)缓存区已满
2)程序正常退出
3)调用fflush函数,强制刷新缓存
4)关闭流
标准输出 stdout
使用行缓存,1k大小,其刷新条件是
1)缓存区已满
2)程序正常退出(包括main函数执行return或程序执行标准库函数exit)
3)调用fflush函数,强制刷新缓存
4)遇到换行符’\n’
标准错误 stderr
无缓存
常用接口
#include <stdio.h>
FILE *fopen(const char *path, const char *mode);
功能:打开指定文件
参数path:文件路径
参数mode:操作模式,如下
"r"读操作,文件若存在则从文件开头读,文件不存在会报错;
"r+"读写操作,文件若存在则从文件开头读写,文件不存在会报错;
"w"写操作,文件若存在则先清空后写入,文件不存在则创建同名文件;
"w+"读写操作,文件若存在则先清空后读写,文件不存在则创建同名文件;
"a"追加写操作,文件若存在则从文件末尾写,文件不存在则创建同名文件;
"a+"追加写和读操作,文件若存在则从文件末尾写,从文件开头读,文件不存在则创建同名文件;
返回:正确返回文件流指针,异常返回NULL并设置errno值。
errno是linux通用类型错误号,其数值与对应的错误绑定,可参考/usr/include/asm-gengeric/errno-base.h文件;
#include <stdio.h>
#include <errno.h>
#include <string.h>
char *strerror(int errnum); //根据errno获取对应的错误描述
void perror(const char *s); //errno对应错误输出
例如perror("fail to open"); 等价于 fprintf(stderr, "fail to open:%s\n", strerror(errno));
int fclose(FILE *fp);
功能:关闭指定文件
返回:正确返回0,异常返回EOF并设置errno值
#define EOF (-1)
数据清空
void bzero(void *s, size_t n);
void *memset(void *s, int c, size_t n);
文件指针操作
int fseek(FILE *stream, long offset, int whence);
功能:偏移文件指针
参数offset:偏移多少个byte,偏移方向取决于offset的正负,负号前移,正号后移。
参数whence:文件指针起始位置,通常设为SEEK_SET(文件开头),SEEK_CUR(当前位置),SEEK_END(文件末尾)。
返回:正确返回0,异常返回EOF并设置errno值。
因此执行fseek后的偏移位置等于(whence+offset),应当注意从文件开头前移或从文件末尾后移都会出现异常。
long ftell(FILE *stream);
功能:获取文件指针当前位置
返回:正确返回当前位置与文件开头相差的byte数,异常返回EOF并设置errno值。
可以使用如下方式计算文件大小
fseek(fp,0,SEEK_END);
printf("size:%ld\n",ftell(fp));
void rewind(FILE *stream);
功能:将文件指针指向文件开头,等同于fseek(fp,0,SEEK_SET);
写操作
int fprintf(FILE *stream, const char *format, ...);
功能:格式化输出到指定文件流,类似于
int printf(const char *format, ...); //格式化输出到标准输出流 stdout
int fputc(int c, FILE *stream); // fputc(int c, stdout); 等价于 putchar(int c);
功能:将字符输出到指定文件流
返回:正确返回字符的ascii码,异常返回EOF
int fputs(const char *s, FILE *stream);
功能:将形参s指向的字符串输出到指定文件流,遇到'\0'结束写入
返回:正常返回非负数,异常返回EOF
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
功能:将形参ptr指向的数据成块写入指定文件流
参数size:指定单个数据块有多少byte
参数nmemb:写入多少个数据块
返回:成功返回写入的块数(通常等于nmemb),异常返回0
读操作
int fgetc(FILE *stream); // fgetc(stdin); 等价于 getchar();
功能:从指定文件流读取一个字符
返回:正确返回字符的ascii码,异常返回EOF
异常返回有以下情况
1、读到文件末尾
2、操作出现错误
因此需要用feof函数做进一步判断
int feof(FILE *stream);
功能:判断是否指向文件末尾
返回:在文件末尾时返回非0,不在文件末尾时返回0
char *fgets(char *s, int size, FILE *stream);
功能:从指定文件流读取一行字符(长度小于形参size),读取到换行符'\n'或者EOF时截止(会读入'\0'和'\n'),并且读取截止后在末尾自动添加'\0'。
参数s:读出的字符串存放在s指向的空间。
返回:正常返回s,异常返回NULL,异常返回的处理方式同fgetc。
如果是读入'\n'后截止,那么字符串末尾就有'\n''\0',通常会用如下方法去掉换行符
if(buf[strlen(buf)-1] == '\n')
buf[strlen(buf)-1] = '\0';
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:从指定文件流成块读取数据
参数ptr:读出的数据存放在ptr指向的空间
参数size:指定单个数据块有多少byte
参数nmemb:读取多少个数据块
返回:成功返回读取的块数(不超过nmemb),异常返回0,异常返回的处理方式同fgetc。
文件IO
特性:
1、系统调用函数
2、属于低级IO,移植性较差
3、不带缓存(实际上有内核缓存)
4、通过文件描述符操作IO
文件描述符:本质上是数组下标(非负整数的索引值),而数组成员就是文件结构体指针;在linux系统中文件描述符的取值范围是0~1023,并且默认0用于标准输入stdin,1用于标准输出stdout,2用于标准错误stderr,因此文件描述符是从3开始分配最小的未使用值。
常用接口
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags); //打开文件
int open(const char *pathname, int flags, mode_t mode); //创建并打开文件
参数pathname:文件路径
参数flags:标志位可分为访问标志(必选其一)、创建标志和状态标志3类,其常用值如下
访问标志
O_RDONLY(只读)
O_WRONLY(只写)
O_RDWR(可读可写)
创建标志
O_CREAT(创建)
O_EXCL(若文件已存在,open创建返回异常)
O_TRUNC(若文件可写,则清空数据)
状态标志
O_APPEND(写追加)
O_NONBLOCK(非阻塞)
fopen的参数mode与flags有如下对应关系
"r" == (O_RDONLY | O_EXCL)
"w" == (O_WRONLY | O_CREAT | O_TRUNC)
"a" == (O_WRONLY | O_CREAT | O_APPEND)
参数mode:创建文件时指定使用权限,通常由以下常量按位或
S_IRWXU == 0700 用户可读可写可执行
S_IRUSR == 0400 用户可读
S_IWUSR == 0200 用户可写
S_IXUSR == 0100 用户可执行
S_IRWXG == 0070 用户组可读可写可执行
S_IRGRP == 0040 用户组可读
S_IWGRP == 0020 用户组可写
S_IXGRP == 0010 用户组可执行
S_IRWXO == 0007 其他人员可读可写可执行
S_IROTH == 0004 其他人员可读
S_IWOTH == 0002 其他人员可写
S_IXOTH == 0001 其他人员可执行
实际上文件最终的使用权限是(mode & ~umask),umask是系统的文件权限掩码。
返回:正确返回文件描述符,异常返回-1并设errno值。
#include <unistd.h>
int close(int fd);
功能:关闭文件,同时回收文件描述符fd
返回:正确返回0,异常返回-1并设errno值
文件指针操作
off_t lseek(int fd, off_t offset, int whence);
功能:偏移文件指针
参数fd:文件描述符
参数offset:偏移多少个byte,偏移方向取决于offset的正负,负号前移,正号后移。
参数whence:文件指针起始位置,通常设为SEEK_SET(文件开头),SEEK_CUR(当前位置),SEEK_END(文件末尾)。
返回:正常返回指针当前位置与文件开头相差的byte数,异常返回-1并设errno值。
写操作
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
功能:将参数buf中的数据写入指定文件
参数fd:文件描述符,索引对应文件
参数count:要写入多少byte数据
返回:正常返回写入的byte数,异常返回-1并设errno值。
读操作
ssize_t read(int fd, void *buf, size_t count);
功能:从文件中读取数据
参数fd:文件描述符,索引对应文件
参数buf:存放读出的数据
参数count:要读取多少byte数
返回:正确返回实际读出多少byte数据,当读取到文件末尾时返回0,异常返回-1并设errno值。
目录操作
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
功能:打开指定目录
参数name:目录名
返回:正常返回目录流指针,异常返回NULL并设errno值。
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
功能:读取目录文件信息
返回值:正常返回文件目录结构体指针,异常返回NULL并设errno值,如果读到目录末尾则返回NULL而且不设errno(默认为0)。
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
功能:关闭目录流
返回:正常返回0,异常返回-1并设errno值。