加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Linux > 正文

Linux中的系统IO函数

发布时间:2020-12-14 01:11:47 所属栏目:Linux 来源:网络整理
导读:一、整体大纲 二、 系统IO函数 1. 一些概念 ? ? 文件描述符 ? ? ?PCB ? ? ?C库函的IO缓冲区 ? ? ?1)?文件描述符 ? ? ? ? ? ? int 类型 ? ? ? ? ? ? 一个进程最多可打开多少文件 ? ? ?2)?pcb ? ? ? ? ? ?进程控制块 ? ? ? ? ? ?在其中有一个文件描述符表 --

一、整体大纲

二、 系统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 filenamen")
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 == %dn",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 filenamen")
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,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 filenamen");
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,sizeof(buf))) != 0)
22     {
23         if (ret == -1)
24         {
25             perror("read err:");
26             return -1;
27         }
28         else
29         {
30             write(STDOUT_FILENO,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,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,sizeof(buf))) != 0)
25     {
26         if (ret == -1)
27         {
28             perror("read err:");
29             return -1;
30         }
31         else
32         {
33             write(STDOUT_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 filenamen");
12         return -1;
13     }
14     int fd = open(argv[1],O_RDONLY);
15 
16     int ret = lseek(fd,SEEK_END); //将fd移动到文件头
17     printf("file size is %dn",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,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 %dn",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,sizeof(buf));
22         if (ret < 0)
23         {
24             perror("read err:");
25             printf("ret is %dn",ret);
26         }
27 
28         if (ret)
29         {
30             printf("buf is %sn",buf);
31         }
32         printf("hahan");
33         sleep(1);
34     }
35     close(fd);
36 
37     return 0;
38 }
使用fcntl函数实现读非阻塞

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读