Linux应用开发(文件IO)

第一节:文件IO与文件描述符

为什么要有两套IO?

  • 标准IO=连锁酒店前台,你只管说给我一间房,细节前台帮你办
  • 文件IO=你自己拿钥匙开门、收拾房间,一点弯路都不走,但什么都要自己干

文件描述符(fd)是什么?

fd就是一个非负整数,是内核给你的号码牌

fd 名字 是什么
0 stdin 标准输入(键盘)
1 stdout 标准输出(屏幕)
2 stderr 标准错误(报错)
这三个是shell默认给你打开的。所以open第一个新文件,拿到的fd一定是3

fd不只是文件

内核用以标识一个特定进程正在访问的文件,其他资源的访问标识,fd是一切资源的统一编号

为什么标准IO能移植?

因为每个操作系统都各自实现了一套C标准库。你在windows上写的fopen,背后是windows自己的实现,不是Linux的,所以移植的是源码,不是二进制

为什么文件IO不能移植?

因为open这个函数只有Linux内核才有,

🔴写open/read/write必须包含<fcntl.h>和<unistd.h>

第二节:open与它的flags

🟠函数原型

复制代码
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

mode(权限)只有在O_CREAT(创建新文件)时才用得上,如果文件已经存在、你也只是读它,权限根本没意义

返回值:

  • 成功:返回fd(非负整数,第一个新文件必然是3)
  • 失败:返回-1,并设置errno

**第一组flags:读写方式(三个值互斥)

flag 名字 效果
O_RDONLY 只读 我只能读它(不能写)
O_WRONLY 只写 我只能写它(不能读
O_RDWR 读写 都可以
比如:
复制代码
int fd = open("a.txt",O_RDONLY);    
int fd = open("a.txt",O_RDONLY | O_WRONLY);    //错误,互斥,不能同时选

O_RDONLY在Linux里面等于0

复制代码
#define O_RDONLY 0  //只读
#define O_WRONLY 1  //只写
#define O_RDWR    //读写

因为flags参数是一个整数,内核用位运算来检查每一位

🟡flags的附加行为

flag 名字 效果 对应fopen模式
O_CREAT 创建 文件不存在就创建新的 w a
O_EXCL 独占 配合O_CREAT:文件已经存在就报错 无
O_TRUNC 截取 文件已存在,把原内容清空 w
O_APPEND 追加 所有写操作强制在文件末尾 a

第三个参数mode:只有O_CREAT才有效

复制代码
int open(const char *pathname, int flags, mode_t mode);

mode是新创建文件的权限,用8进制表示:

八进制 二进制 含义
6 110 读写
4 100 只读
7 111 读写执行

对照表:fopen模式=== open flags

fopen模式 对应的open写法
r open(path,O_RDONLY)
r+ open(path,O_RDWR)
w open(path,O_WRONLY | O_CREAT | O_TRUNC, 0664)
w+ open(path,O_RDWR | O_CREAT | O_TRUNC, 0664)
a open(path, O_WRONLY | O_CREAT | O_APPEND, 0664)
a+ open(path, O_RDWR | O_CREAT | O_APPEND, 0664)

close关闭文件

复制代码
int close(int fd);
  • 成功:返回0
  • 失败:返回-1并设置errno

第三节:read与write

函数原型

复制代码
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf,size_t count);

三个参数,含义完全一样,只是方向不同:

参数 读 写
fd 从哪个fd读 往哪个fd写
buf 数据读到这里 数据从这里写出去
count 最多读多少字节 最多写多少字节

返回值

复制代码
ssize_t n = read(fd,buf,sizeof(buf));
返回值 含义
>0 实际读写的字节数
=0 读:读到文件末尾/写:什么都没写进去
=-1 出错了,设置errno
🔴关键:read的返回值永远不超过count
read是同步调用,读完才返回,会一直读到读满1024或文件到末尾才停。最多只能给你实际有点哪些

read为什么是阻塞的

复制代码
n = read(fd,buf,1024);

如果文件里面只有500字节,这一行会立刻返回500吗?会

但是如果fd是个"管道"或者"socket",那就不一定,read会一直等,等到有数据来才返回,这就是阻塞

所以read的行为分为两种:

fd类型 read的行为
普通文件 到末尾就返回,不阻塞
管道、socket、终端 阻塞,等有数据、有连接、有输入才返回

read/write的一个副作用:会移动文件的位置

read之后,光标自动往前移

复制代码
lseek(fd,0,SEEK_END);                  //光标顶到末尾
printf("%ld\n",lseek(fd,0,SEEK_CUR));  //打印文件的大小
ssize_t n = read(fd,buf,100);          //读最后100字节
printf("%ld\n",lseek(fd,0,SEEK_CUR));  //位置变了

第四节:lseek---一个函数干两件事

第一章的定位方法是分两步:

复制代码
fseek(fp,576,SEEK_SET);           //第一步:挪位置
long pos = ftell(fp);             //第二步:问位置

lseek把这两件事合并成了一个原子操作:

复制代码
off_t pos = lseek(fd,576,SEEK_SET);     //挪完之后,直接告诉你挪到哪里

大白话:fseek像你自己走过去,ftell像你问自己在哪;lseek像你跟司机说送我到22号,司机顺口告诉你到了22号

函数原型:

复制代码
off_t lseek(int fd, off_t offset, int whence);

三个参数和fseek一模一样,返回值:

函数 成功返回 失败返回
fseek 0 -1
lseek 新的文件位置 -1
所以正确的写法:
复制代码
off_t pos = lseek(fd,576,SEEK_SET);
if(pos == (off_t)-1){    //必须和-1比较,而不是0,因为只有刚好定位到0字节才会返回0
	perror("lseek");
	exit(-1);
}
printf("定位成功\n");

🔴这里为什么要写(off_t)-1,而不是直接写-1?因为严格来说off_t可能有符号有可能没有符号

三个whence

whence 基准点 lseek(fd,0,X)的效果
SEEK_SET 文件开头 跳到开头,返回0
SEEK_CUR 当前位置 原地不动,返回当前位置
SEEK_END 文件末尾 跳到末尾,返回文件大小

第五节:fdopen---打通两套体系

fdopen的作用:一个补办手续的函数

问题的场景:我用open拿到了fd,但我现在想用fgets、fprintf这些好用的标准IO函数

复制代码
FILE *fdopen(int fd,const *mode);
  • 成功:返回一个FILE *(这个背后装的就是fd)
  • 失败:返回NULL并设置errno:fdopen不会复制内容,他只是给已有的fd套上一个FILE结构体

mode参数写什么?mode必须和open时用的flags兼容

为什么不能随便写:因为FILE结构体里记着我现在能读还是写,如果open时,只申请了只读权限,fdopen却告诉库函数他能写,那么真写的时候就会报错

只能单向,没有openfp

常规是把文件IO转成标准IO

因为fopen内部已经做好了一个完整的FILE结构体,里面还包着一个fd,完全可以直接访问这个fd

因为fopen虽然操作fd,但它返回的是FILE*,属于标准IO家庭,所以归stdio.h管

相关推荐
小范的技术工坊2 小时前
Linux应用开发(文件属性)
linux·运维·服务器
wuminyu2 小时前
JMM学习总结:深入理解happens-before关系
java·linux·c语言·jvm·c++
科芯创展3 小时前
XZ1824 宽电压150V 10A开关降压DC-DC控制器技术解析
单片机
高晶4 小时前
ARM 嵌入式 Linux 文件系统从入门到实战:目录结构、权限管理、选型与挂载排查全攻略
linux·程序员
Zwawa4 小时前
让电机走到指定位置:编码器位置环 PID
c语言·单片机·嵌入式
运维全世界4 小时前
Slurm集群搭建实战踩坑:存储节点无RAID、跨节点GPU无法读取数据彻底解决
linux
帷幕落秋4 小时前
进程服务与文件描述符
linux·运维·面试
用户209583592304 小时前
谛听(Diting)开发W7:检出率从 27% 到 100%,规则包从 19 条扩到 27 条
linux
桀人4 小时前
I2C概念引入
stm32·单片机·嵌入式硬件