Linux C编程之七(2) 系统IO函数
一、整体大纲
二、 系统IO函数
1. 一些概念
文件描述符
PCB
C库函的IO缓冲区
1) 文件描述符
int 类型
一个进程最多可打开多少文件
2) pcb
进程控制块
在其中有一个文件描述符表 -- 数组[1024]
C库IO函数工作流程:
pcb和文件描述符:
2. 虚拟地址空间
虚拟地址空间就是程序启动起来之后从硬盘上会有一块虚拟内存分配出来。
cpu 为什么要使用虚拟地址空间与物理地址空间映射?解决了什么样的问题?
1)方便编译器和操作系统安排程序的地址分布。
程序可以使用一系列相邻的虚拟地址来访问物理内存中不相邻的大内存缓冲区。通过虚拟地址空间与物理地址空间映射解决不连续的缓冲区的问题。
2)方便进程之间隔离
不同进程使用的虚拟地址彼此隔离。一个进程中的代码无法更改正在由另一进程使用的物理内存。
3)方便OS使用你那可怜的内存。
程序可以使用一系列虚拟地址来访问大于可用物理内存的内存缓冲区。当物理内存的供应量变小时,
内存管理器会将物理内存页(通常大小为 4 KB)保存到磁盘文件。数据或代码页会根据需要在物理内存与磁盘之间移动。
虚拟地址空间的布局如下:
0-3G是用户空间 3-4G是内核空间
用户区 内核区
代码段
已经初始化的全局变量
未被初始化的全局变量
堆 -- 从下往上
共享库
栈 - 从上往下
环境变量
内核区
3. C库函数与系统函数的关系
FD:文件描述符 FP_POS:文件指针 BUFFER:缓冲区
write对0-3G的用户空间进行操作 sys_write()对3-4G的内核空间进行操作
4. IO函数介绍
1)open
- 查看 man 2 open
- 头文件:
#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
必选项:
O_RDONLY 只读
O_WRONLY 只写
O_RDWR 读写
可选项:
O_APPEND 追加
O_CREAT 创建文件
O_EXCL和O_CREATE一起使用,如果文件存在则报错
O_NONBLOCK 非阻塞
Mode 权限位,最终(mode&~umask)
- 返回值:
成功:返回最小的可用文件描述符
失败:返回-1,并且设置errno
- open函数中的errno:
1 #include<stdio.h> 2 #include<fcntl.h> 3 #include<sys/types.h> 4 #include<sys/stat.h> 5 #include<unistd.h> 6 7 int main(int argc, char *argv[]) 8 { 9 if (argc != 2) 10 { 11 printf("./a.out filename\n") 12 return -1 13 } 14 int fd = open(argv[1], O_CREAT|O_TRUNC|O_WRONLY, 0666); 15 close(fd); 16 17 return 0; 18 }
使用open实现一个touch功能
1 #include<stdio.h> 2 #include<unistd.h> 3 #include<sys/types.h> 4 #include<sys/stat.h> 5 #include<fcntl.h> 6 #include<strings.h> 7 8 int main(int argc, char *argv[]) 9 { 10 int num = 3; 11 char filename[128] = {0}; 12 while(1) 13 { 14 sprintf(filename, "temp_%04d", num++); 15 if (open(filename, O_RDONLY|O_CREAT, 0666) < 0) 16 { 17 perror("open err:"); 18 break; 19 } 20 } 21 printf("num == %d\n", num); 22 23 return 0; 24 }
一个进程打开的最大文件数(1024)
2)close
- 作用:关闭文件描述符
- 头文件:
#include <unistd.h>
- 函数原型:
int close(int fd);
- 参数说明:
fd文件描述符
- 返回值:
成功:返回0
失败:返回-1,并且设置errno
3)read读
- 头文件
#include <unistd.h>
- 函数原型
ssize_t read(int fd, void *buf, size_t count);
- 参数说明
fd 文件描述符
buf缓冲区
count缓冲区大小
- 返回值
失败:返回-1,设置errno
成功:返回读到的字节数
0代表读到文件末尾
非阻塞的情况下read返回-1,但是此时需要判断error的值。
4)write写
- 头文件
#include <unistd.h>
- 函数原型
ssize_t write(int fd, const void *buf, size_t count);
- 参数说明:
fd文件描述符
buf缓冲区
count缓冲区大小
- 返回值
失败:返回-1,设置errno
成功:返回写入的字节数
0代表未写入
1 #include<stdio.h> 2 #include<fcntl.h> 3 #include<sys/types.h> 4 #include<sys/stat.h> 5 #include<unistd.h> 6 7 int main(int argc, char *argv[]) 8 { 9 if (argc != 2) 10 { 11 printf("./a.out filename\n") 12 return -1 13 } 14 int fd = open(argv[1], O_RDONLY); 15 char buf[256] = {0}; 16 int ret = 0; 17 while ((ret = read(fd, buf, ziseof(buf))) != 0) 18 { 19 if (ret == -1) 20 { 21 perror("read err:"); 22 return -1; 23 } 24 else 25 { 26 write(STDOUT_FILENO, buf, ret); 27 } 28 } 29 30 close(fd); 31 32 return 0; 33 }
实现一个cat功能
需求:给一个文件中写入内容,写完之后打开该文件再读取写入的内容?
1 #include<stdio.h> 2 #include<fcntl.h> 3 #include<sys/types.h> 4 #include<sys/stat.h> 5 #include<unistd.h> 6 7 int main(int argc, char *argv[]) 8 { 9 if (argc != 2) 10 { 11 printf("./a.out filename\n"); 12 return -1; 13 } 14 int fd = open(argv[1], O_RDWR|O_CREAT, 0666); 15 16 char data[12] = "hello world"; 17 write(fd, data, sizeof(data)); 18 19 char buf[256] = {0}; 20 int ret = 0; 21 while ((ret = read(fd, buf, sizeof(buf))) != 0) 22 { 23 if (ret == -1) 24 { 25 perror("read err:"); 26 return -1; 27 } 28 else 29 { 30 write(STDOUT_FILENO, buf, ret); //STDIN_FILENO, STDERR_FILENO 31 } 32 } 33 34 close(fd); 35 36 return 0; 37 }
bug版本
结果:内容写入到文件中,但是并未按预期输出到屏幕上。
原因:是由于write完成之后,fd到了文件末尾,因此read时到了文件末尾,无法读取文件数据
解决方法:写完之后将文件指针设置到文件开头,使用请看下文要介绍的lseek函数。
5)lseek写
- 头文件
#include <sys/types.h> #include <unistd.h>
- 函数原型
off_t lseek(int fd, off_t offset, int whence);
- 参数说明
fd文件描述符
offset偏移量
whence:
SEEK_SET 文件开始位置
SEEK_CUR 文件当前位置
SEEK_END 文件结尾
- 返回值
失败:返回-1,设置errno
成功:返回当前位置到文件开头的长度
- lseek作用
移动文件读写位置
计算文件大小
拓展文件
示例:
a. 移动文件读写位置
1 #include<stdio.h> 2 #include<fcntl.h> 3 #include<sys/types.h> 4 #include<sys/stat.h> 5 #include<unistd.h> 6 7 int main(int argc, char *argv[]) 8 { 9 if (argc != 2) 10 { 11 printf("./a.out filename\n"); 12 return -1; 13 } 14 int fd = open(argv[1], O_RDWR|O_CREAT, 0666); 15 16 char data[12] = "hello world"; 17 write(fd, data, sizeof(data)); 18 //文件读写位置此时在末尾 19 //需要移动读写位置 20 lseek(fd, 0, SEEK_SET); //将fd移动到文件头 21 22 char buf[256] = {0}; 23 int ret = 0; 24 while ((ret = read(fd, buf, sizeof(buf))) != 0) 25 { 26 if (ret == -1) 27 { 28 perror("read err:"); 29 return -1; 30 } 31 else 32 { 33 write(STDOUT_FILENO, buf, ret); //STDIN_FILENO, STDERR_FILENO 34 } 35 } 36 37 close(fd); 38 39 return 0; 40 }
修改上例的bug(写入文件内容并读取文件内容打印到屏幕)
b. 计算文件大小
1 #include<stdio.h> 2 #include<fcntl.h> 3 #include<sys/types.h> 4 #include<sys/stat.h> 5 #include<unistd.h> 6 7 int main(int argc, char *argv[]) 8 { 9 if (argc != 2) 10 { 11 printf("./a.out filename\n"); 12 return -1; 13 } 14 int fd = open(argv[1], O_RDONLY); 15 16 int ret = lseek(fd, 0, SEEK_END); //将fd移动到文件头 17 printf("file size is %d\n", ret); //注意实际读到的文件大小为ret-1 18 19 close(fd); 20 21 return 0; 22 }
计算文件大小(输出文件字节数)
c. 拓展文件
1 #include<stdio.h> 2 #include<fcntl.h> 3 #include<sys/types.h> 4 #include<sys/stat.h> 5 #include<unistd.h> 6 7 int main(int argc, char *argv[]) 8 { 9 if (argc != 2) 10 { 11 printf("./a.out filename\n"); 12 return -1; 13 } 14 int fd = open(argv[1], O_WRONLY|O_CREAT, 0666); 15 //拓展文件 16 int ret = lseek(fd, 1024, SEEK_END); //将fd移动到文件头 17 //需要至少写一次,否则不能保存 18 write(fd, "a", 1); 19 printf("file size is %d\n", ret); 20 21 close(fd); 22 23 return 0; 24 }
拓展文件
阻塞的概念:
read函数在读设备或者读管道,或者读网络的时候。
输入输出设备对应的/dev/tty。
6)fcntl
- 头文件
#include <unistd.h> #include <fcntl.h>
- 函数原型
int fcntl(int fd, int cmd, ... /* arg */ );
- 参数说明:
fd文件描述符
cmd 命令
- 返回值
不同的cmd返回值不同
1 #include<stdio.h> 2 #include<fcntl.h> 3 #include<sys/types.h> 4 #include<sys/stat.h> 5 #include<unistd.h> 6 7 int main(int argc, char *argv[]) 8 { 9 //O_NONBLOCK设置为非阻塞 10 int fd = open("/dev/tty", O_RDWR); 11 //fcntl()函数,设置非阻塞 12 int flags = fcntl(fd, F_GETFL); 13 flags |= O_NONBLOCK; 14 fcntl(fd, F_SETFL, flags); 15 16 char buf[256] = {0}; 17 int ret = 0; 18 while(1) 19 { 20 //如果没有设置O_NONBLOCK 21 ret = read(fd, buf, sizeof(buf)); 22 if (ret < 0) 23 { 24 perror("read err:"); 25 printf("ret is %d\n", ret); 26 } 27 28 if (ret) 29 { 30 printf("buf is %s\n", buf); 31 } 32 printf("haha\n"); 33 sleep(1); 34 } 35 close(fd); 36 37 return 0; 38 }
使用fcntl函数实现读非阻塞
转载于:https://www.cnblogs.com/xuejiale/p/10788695.html
Linux C编程之七(2) 系统IO函数相关推荐
- 【Linux系统编程学习】C库IO函数与系统IO函数的关系
此为黑马Linux课程笔记. 1. C标准IO函数工作流程 如图,以C库函数的fopen为例,其返回类型是FILE类型的指针,FILE类型包含很多内容,主要包含三个内容:文件描述符.文件读写指针的位置 ...
- 【Linux系统IO函数】lseek函数
Linux系统IO函数-lseek函数 1.1 lseek函数与标准C库的fseek函数 lseek函数对应标准C库中的fseek函数 查看标准C库中的fseek函数使用说明: (shell输入) m ...
- 标准C库IO函数和Linux系统IO函数对比
标准C库IO函数和Linux系统IO函数对比 man 3 fopen #查看函数详情 虚拟地址通过mmu映射到真是的地址空间
- linux PCB数组,Linux中的系统IO函数
一.整体大纲 二. 系统IO函数 1. 一些概念 文件描述符 PCB C库函的IO缓冲区 1) 文件描述符 int 类型 一个进程最多可打开多少文件 2) pcb 进程控制块 在其中有一个文件描述符表 ...
- Linux部分系统IO函数
1.系统IO函数: (1)open函数: 1).首先其需要包含头文件: #include<sys/types.h> #include<sys/stat.h> #include& ...
- Linux io模型及函数调用,Linux 网络编程的5种IO模型:信号驱动IO模型
Linux 网络编程的5种IO模型:信号驱动IO模型 背景 这一讲我们来看 信号驱动IO 模型. 介绍 情景引入: 在信号驱动IO模型中,当用户线程发起一个IO请求操作,会给对应的socket注册一个 ...
- Linux C/C++编程之(十三)系统IO函数
文章目录 一.概述 二.当头棒喝 三.函数概述 四.IO函数介绍 1)open 2)close 3)read 4)write 5)lseek 6)fcntl 五.利用IO函数实现一个copy函数 一. ...
- Linux多任务编程之七:Linux守护进程及其基础实验(转)
来源:CSDN 作者:王文松 转自Linux公社 ------------------------------------------------------------------------- ...
- linux文件编程(3)—— main函数传参、myCp(配置成环境变量)、修改配置文件、整数和结构体数组写到文件
参考:linux文件编程(3)-- 文件编程的简单应用:myCp.修改配置文件 作者:丶PURSUING 发布时间: 2021-04-09 23:45:05 网址:https://blog.csdn. ...
- 应用编程课程4.系统IO和标准IO的比较,自己做的一些理解,仅仅方便自己看
/* 1.注意fseek实际上是调用lseek来实现的, 比较以下标准io与文件io的区别 注意:在stream这个概念中,有三个标准流stdin.stdout.stderr,,在我们当前这个文件描述 ...
最新文章
- 阿里云 rds 在windows 里面恢复
- VTK修炼之道60:体绘制_体绘制管线图形渲染管线
- iOS Hacker 使用Theos开发tweak
- 从无盘启动看 Linux 启动原理
- JAVA入门级教学之(IDEA工具的快捷键和简单设置)
- java传递实例_Java方法的参数传递机制实例详解
- dlna和miracast可以共存吗_高考化学必备之离子共存问题
- Extra }, or forgotten endgroup. [ maketitlepage]问题的解决(uline命令)
- java压缩文件夹(含有空文件夹)
- 背包笔记及Java实现
- 用JCreator编写java程序
- Ventoy+WePE 装机教程(装PVE+ESXI等,不用单独费一个U盘)
- JVM垃圾回收机制 (垃圾判断,垃圾回收算法,垃圾回收器,五种引用)【jvm】
- python写监控脚本_python写个进程监控的脚本
- 吃握手包的电子宠物 - Pwnagotchi开箱教程
- AR unity制作阴影
- filecoin lotus 转账fil流程和gas计算
- OpenGL 纹理基础与索引
- java计算机毕业设计黑格伯爵国际英语贵族学校官网源码+mysql数据库+系统+lw文档+部署
- 0基础光缆/光纤熔接教程
热门文章
- NYOJ --21--三个水杯
- NYOJ--458 小光棍数
- underscore 系列之内部函数 restArgs
- SQL时间相关 - SQL日期,时间比较(转)
- 官网下载到离线的Adobe Acrobat Reader DC
- WINDOWS上svn服务器自动部署
- 配置管理小报091103-2: CVS中的tag规则
- matlab分析具体问题论文,matlab论文12010245327马文建.doc
- java项目 干洗店源码,基于jsp的干洗店管理系统-JavaEE实现干洗店管理系统 - java项目源码...
- 业务流程图_你会用Visio制作专业的业务流程图吗?