Linux高级文件操作 -1

本文探讨了Linux中阻塞I/O与非阻塞I/O的工作原理及实现方式,通过具体示例展示了如何使用这两种I/O模型从多个管道中读取数据,并分析了它们之间的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Linux中的文件备用来完成大量任务:

  • 正常的文件中保持久的数据
  • 通过套接字进行网络通讯
  • 通过设备文件来访问设备
  • ,,,

    多路输入输出

阻塞I/O

首先创建两个管道,命名p1和p2(使用mknod命令), 然后在两个终端分别运行cat > p1和 cat > p2。在第三个终端上运行程序mpx-blocks。
运行结果是在每个cat窗口键入文字输入,程序的表现是,在每一行输入结束前,两个cat窗口中的命令是不会把任何数据写到管道中的。
这里写图片描述
这里写图片描述
这里写图片描述

/* mpx-blocks.c - Displays input from two pipes, alternatively */

#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main(void) {
    int fds[2];
    char buf[4096];
    int i;
    int fd;

    if ((fds[0] = open("p1", O_RDONLY)) < 0) {
        perror("open p1");
        return 1;
    }

    if ((fds[1] = open("p2", O_RDONLY)) < 0) {
        perror("open p2");
        return 1;
    }

    fd = 0;
    while (1) {
        /* if data is available read it and display it */
        i = read(fds[fd], buf, sizeof(buf) - 1);
        if (i < 0) {
            perror("read");
            return 1;
        } else if (!i) {
            printf("pipe closed\n");
            return 0;
        } 

        buf[i] = '\0';
        printf("read: %s", buf);

        /* read from the other file descriptor */
        fd = (fd + 1) % 2;
    }
}

上述程序同一时刻只能从一个管道中读取数据,同时从一个管道中读取数据的时候一直被阻塞住另一个管道文件被忽略,直到该文件中有了数据read之后并返回,这个方法表现出来的行为读取数据并不是很流畅的数据多路传输。

非阻塞I/O

通过系统调用fcntl()可以来指定一个文件是非阻塞的。当一个文件是非阻塞的时候,read总是可以立即返回,如果没有现成的数据,仅仅简单地返回一个0。非阻塞I/O通过避免文件上的操作阻塞而为多路传输提供了一个简单的方法。
基于上面的程序进行修改:

/* mpx-nonblock.c - Displays input from two pipes via nonblocking I/O */

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main(void) {
    int fds[2];
    char buf[4096];
    int i;
    int fd;

    /* open both pipes in nonblocking mode */
    if ((fds[0] = open("p1", O_RDONLY | O_NONBLOCK)) < 0) {
        perror("open p1");
        return 1;
    }

    if ((fds[1] = open("p2", O_RDONLY | O_NONBLOCK)) < 0) {
        perror("open p2");
        return 1;
    }

    fd = 0;
    while (1) {
        /* if data is available read it and display it */
        i = read(fds[fd], buf, sizeof(buf) - 1);
        if ((i < 0) && (errno != EAGAIN)) {
            perror("read");
            return 1;
        } else if (i > 0) {
            buf[i] = '\0';
            printf("read: %s", buf);
        }

        /* read from the other file descriptor */
        fd = (fd + 1) % 2;
    }
}

阻塞和非阻塞之间的区别在于,非阻塞的时候它读取的管道关闭时候它并不退出。从没有任何写入者的管道读取数据的时候非阻塞read会返回0个字节数;从一个有写入者但没有数据管道读取数据的时候read返回EAGAIN。

缺点:虽然非阻塞的I/O很容易地在文件描述符之间切换,也付出了很大的系统消耗代价,程序不停地在运行,永远不会阻塞,不断地轮询哪个文件可以读取,进程一直在运行不会休眠。

//1.创建文件file1,写入字符串“abcdefghijklmn”; //2.创建文件file2,写入字符串“ABCDEFGHIJKLMN”; //3.读取file1中的内容,写入file2,使file2中的字符串内容为“abcdefghijklmn ABCDEFGHIJKLMN” 创建新文件,该文件具有用户读写权限。 //2.采用dup/dup2/fcntl复制一个新的文件描述符,通过新文件描述符向文件写入“class_name”字符串; //3.通过原有的文件描述符读取文件中的内容,并且打印显示; 1.输入文件名称,能够判断文件类型,判断实际用户对该文件具有哪些存取权限; ?2.要求打印出文件类型信息,inode节点编号,链接数目,用户id,组id,文件大小信息; ?3.修改文件的权限为当前用户读写,组内用户读写,组外用户无权限 新建文件,设置文件权限屏蔽字为0; 2.建立该文件的硬链接文件,打印硬链接文件的inode节点号和文件大小; ? 3.建立该文件的软链接文件,打印软链接文件的inode节点号和文件大小;打印软链接文件中的内容; 4.打印源文件的inode节点号,文件大小和链接数目; ? 5.调用unlink对源文件进行操作,打印源文件链接数目; .新建/home/user目录; 2.把当前工作路径移至/home/user目录; 3.打印当前工作路径; ?编写程序完成以下功能: ?1.递归遍历/home目录,打印出所有文件和子目录名称及节点号。 ?2.判断文件类型,如果是子目录,继续进行递归遍历,直到遍历完所有子目录为止
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值