导图社区 系统IO函数
为了给设备和磁盘文件提供一个更高层更有效的接口,Linux提供了一系列的标准函数库。下图介绍了C语言文件IO函数、Linux系统IO函数。
编辑于2021-08-21 01:29:57前言
C语言文件IO函数
C语言文件IO函数 带有缓冲区
C语言的文件IO函数 会调用 系统IO函数(Linux环境下)
Linux系统IO函数
系统函数并不是内核函数,系统函数会向下调用 内核函数
系统IO函数 不带有缓冲区,而是用户自己指定缓冲区大小
C库函数
打开文件
函数:FILE *fopen(char *filename, char *mode);
读取文件内容
单个字符读取
函数:int fgetc (FILE *fp);
字符串(按行)读取
函数:char *fgets ( char *str, int n, FILE *fp );
数据块的形式读取
函数:size_t fread ( void *ptr, size_t size, size_t count, FILE *fp );
格式化读取
函数:int fscanf ( FILE *fp, char * format, ... );
随机读取
需要移动文件指针的位置,来达到你想要的位置,然后进行读操作
将内容写入文件
单个字符写入
函数:int fputc ( int ch, FILE *fp );
字符串(按行)写入
函数:int fputs( char *str, FILE *fp );
数据块的形式写入
函数:size_t fwrite ( void * ptr, size_t size, size_t count, FILE *fp );
格式化写入
函数:int fprintf ( FILE *fp, char * format, ... );
随机写入
需要移动文件指针的位置,来达到你想要的位置,然后进行写操作
关闭文件
函数:int fclose(FILE *fp);
demo3:C语言获取文件长度
demo2:C语言插入、删除、更改文件内容
demo1:实现文件复制
思路:将源文件打开,读取源文件内容,然后写入目标文件内容
c++ 文件IO
输入输出流
文件操作
Linux系统IO函数
打开磁盘文件
函数:open函数
注意:1. open是一个系统函数, 只能在linux系统中使用, windows不支持2. fopen 是标准c库函数, 一般都可以跨平台使用, 可以这样理解: - 在linux中 fopen底层封装了Linux的系统API open - 在window中, fopen底层封装的是 window 的 api
函数原型:int open(const char *pathname, int flags);int open(const char *pathname, int flags, mode_t mode);头文件:#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>
pathname:文件的相对或绝对路径
flags:打开方式
必选项
O_RDONLY 只读打开
O_WRONLY 只写打开
O_RDWR 可读可写打开
互斥
可选项
O_APPEND 表示追加。
如果文件已有内容,这次打开文件所写的数据附加到文件的末尾而不覆盖原来的内容。
O_CREAT 若此文件不存在则创建它。
使用此选项时需要提供第三个参数mode,表示该文件的访问权限。
文件权限由open的mode参数和当前进程的umask掩码共同决定
0777 & (~0002) = 0775 111111111 111111101& 111111101
O_EXCL 如果同时指定了O_CREAT,并且文件已存在,则出错返回。
O_TRUNC 如果文件已存在,则将其长度截断(Truncate)为0字节。
O_NONBLOCK 设置文件为非阻塞状态
头文件:fcntl.h
常见错误
1. 打开文件不存在
2. 以写方式打开只读文件(打开文件没有对应权限)
3. 以只写方式打开目录
对文件操作1:读取文件内容
函数:read函数
ssize_t read(int fd, void *buf, size_t count);头文件:#include <unistd.h>
参数:- fd: 文件描述符, open() 函数的返回值, 通过这个参数定位打开的磁盘文件- buf: 是一个传出参数, 指向一块有效的内存, 用于存储从文件中读出的数据 --传出参数: 类似于返回值, 将变量地址传递给函数, 函数调用完毕, 地址中就有数据了- count: buf指针指向的内存的大小, 指定可以存储的最大字节数
返回值:- 大于0: 从文件中读出的字节数,读文件成功- 等于0: 代表文件读完了,读文件成功- -1: 读文件失败了
对文件操作2:将内容写入文件中
函数:write函数
ssize_t write(int fd, const void *buf, size_t count);头文件:#include <unistd.h>
参数:- fd: 文件描述符, open() 函数的返回值, 通过这个参数定位打开的磁盘文件- buf: 指向一块有效的内存地址, 里边有要写入到磁盘文件中的数据 - count: 要往磁盘文件中写入的字节数, 一般情况下就是buf字符串的长度, strlen(buf)
返回值:- 大于0: 成功写入到磁盘文件中的字节数- -1: 写文件失败了
对文件操作3:移动文件指针(对文件拓展)
函数:lseek函数
off_t lseek(int fd, off_t offset, int whence);头文件:#include <sys/types.h>#include <unistd.h>
参数:
int fd --> 文件描述符
off_t offset --> 偏移量
int whence --> 偏移位置
SEEK_SET - 从文件头向后偏移
SEEK_CUR - 从当前位置向后偏移
SEEK_END - 从文件尾部向后偏移
返回值:- 成功: 文件指针从头部开始计算总的偏移量- 失败: -1
demo
1 文件指针移动到文件头部
lseek(fd, 0, SEEK_SET);
2 得到当前文件指针的位置
lseek(fd, 0, SEEK_CUR);
3 得到文件总大小
lseek(fd, 0, SEEK_END);
4 文件拓展
应用场景:假设使用一个下载软件进行一个大文件下载,但是磁盘很紧张,如果不能马上将文件下载到本地,磁盘空间就可能被其他文件占用了,导致下载软件下载的文件无处存放。那么这个文件怎么解决呢?我们可以在开始下载的时候先进行文件拓展,将一些字符写入到目标文件中,让拓展的文件和即将被下载的文件一样大,这样磁盘空间就被成功抢到手,软件就可以慢悠悠的下载对应的文件了。
实现:
使用 lseek 函数进行文件拓展必须要满足一下条件:1. 文件指针必须要偏移到文件尾部之后, 多出来的就需要被填充的部分。2. 文件拓展之后,必须要使用 write()函数进行一次写操作(写什么都可以,没有字节数要求)。
代码:// lseek.c// 拓展文件大小#include <stdio.h>#include <fcntl.h>#include <unistd.h>int main(){ int fd = open("hello.txt", O_RDWR); if(fd == -1) { perror("open"); return -1; } // 文件拓展, 一共增加了 1001 个字节 lseek(fd, 1000, SEEK_END); write(fd, " ", 1); close(fd); return 0;}
对文件操作4:对文件拓展 | 文件截断
函数:truncate/ftruncate函数
int truncate(const char *path, off_t length);int ftruncate(int fd, off_t length);头文件:#include <unistd.h>#include <sys/types.h>
两个函数的区别:truncate() 和 ftruncate() 两个函数的区别在于一个使用文件名一个使用文件描述符操作文件, 功能相同。不管是使用这两个函数还是使用 lseek() 函数拓展文件,文件尾部填充的字符都是 0。
参数:- path: 要拓展/截断的文件的文件名;- fd: 文件描述符, open() 得到的;- length: 文件的最终大小 - 文件原来size > length,文件被截断, 尾部多余的部分被删除, 文件最终长度为length - 文件原来size < length,文件被拓展, 文件最终长度为length
返回值: 成功返回0; 失败返回值-1
关闭磁盘文件
函数:close函数
int close(int fd);头文件:#include <unistd.h>
描述:1. 参数:d 是文件描述符, 是open() 函数的返回值2. 返回值:函数调用成功返回值 0, 调用失败返回 -1
需知:在Linux系统中必须要使用系统提供的IO函数才能基于这些文件描述符完成对相关文件的读写操作。这些Linux系统IO函数和标准C库的IO函数使用方法类似,函数名称也类似,下边开始一一介绍。
系统函数的返回值处理
说明:在查看Linux系统函数的时候, 我们可以发现一个规律: 大部分系统函数的返回值都是整形,并且通过这个返回值来描述系统函数的状态(调用是否成功了)。在man 文档中关于系统函数的返回值大部分时候都是这样描述的:
errno
头文件:这个错误号存储在系统的两个头文件中:/usr/include/asm-generic/errno-base.h/usr/include/asm-generic/errno.h
得到错误号,去查询对应的头文件
第 1 - 34 个错误定义:/usr/include/asm-generic/errno-base.h
errno-base.h 错误定义的一部分
第 35 - 133 个错误定义:/usr/include/asm-generic/errno.h
perror
得到错误号,去查询对应的头文件是非常不方便的,我们可以通过 perror 函数将错误号对应的描述信息打印出来
#include <stdio.h>// 参数, 自己指定这个字符串的值就可以, 指定什么就会原样输出, 除此之外还会输出错误号对应的描述信息void perror(const char *s);
用来将上一个函数发生错误的原因输出到标准设备(stderr)
用来将上一个函数发生错误的原因输出到标准设备(stderr)