Linux驱动开发之Read_Write函数

引言

在Linux字符设备驱动开发中,read和write是最基础的数据交互接口。它们分别实现从设备读取数据和向设备写入数据的功能,是连接用户空间与内核空间的桥梁。本文将简单介绍这两个函数的基本用法和实现要点。

Read函数

其函数原型为:

cs 复制代码
#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

(先重点强调一下,使用该函数必须要引用对应的头文件。)

看得出来,该函数仍是一个含参数且有返回值的函数。

参数int fd

这个应该有点印象了,表示要读取的文件描述符。

参数void* buf

表示存放读取数据的缓冲区指针。

参数size_t count

表示期望读取的最大字节数。

返回值

刚开始我还以为是size_t,结果是ssize_t。它表示返回有符号整数。如果该返回值大于0,表示成功读取的字节数;如果等于0,则表示已达文件末尾;如果等于-1,则表示读取失败。

Write函数

其函数原型为:

cs 复制代码
#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);

下面是该函数的简要介绍:

参数int fd

表示要写入的文件描述符。

参数 void* buf

表示存放待写入数据的缓冲区指针。

参数size_t count

表示期望写入的最大字节数。

返回值

如果该返回值大于0,表示成功写入的字节数;如果等于0,则表示未写入任何数据;如果等于-1,则表示写入失败。

使用示例

cs 复制代码
// 包含系统调用所需的头文件
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "unistd.h"
#include "stdio.h"

int main(int argc, char** argv)
{
    int fd1, fd2;          // 文件描述符,fd1 用于源文件,fd2 用于目标文件
    char buf[512];         // 数据缓冲区,用于暂存从源文件读取的数据
    int read_size;         // 记录每次实际读取的字节数

    // 检查命令行参数数量是否正确
    // 程序需要 2 个参数:源文件路径和目标文件路径,加上程序名本身,argc 必须等于 3
    if (argc != 3)
    {
        printf("error!\r\n");
        return -1;
    }

    // 以只读方式打开源文件
    fd1 = open(argv[1], O_RDONLY);
    // 以只写方式打开或创建目标文件
    // O_TRUNC:如果文件存在,清空其内容;O_CREAT:如果文件不存在,创建它;0666:设置文件权限
    fd2 = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0666);

    // 检查文件是否成功打开
    // open 函数失败时返回 -1,成功时返回一个非负整数的文件描述符
    if (fd1 < 0 || fd2 < 0)
    {
        printf("open error!\r\n");
        return -1;
    }

    // 无限循环,直到读取到文件末尾
    while (1)
    {
        // 从源文件读取数据到缓冲区
        // sizeof(buf) 表示期望读取的最大字节数
        read_size = read(fd1, buf, sizeof(buf));

        // 如果 read_size 为 0,表示已经读到文件末尾,退出循环
        if (read_size == 0)
        {
            break;
        }

        // 将读取到的数据写入目标文件
        // read_size 表示实际写入的字节数,确保只写入刚读到的有效数据
        write(fd2, buf, read_size);
    }

    // 关闭文件描述符,释放系统资源
    close(fd1);
    close(fd2);

    return 0;
}

解释一下,首先是系统所需要的头文件,这个是代码中最重要的部分。然后就是定义文件描述符,数据缓冲区以及实际读取到的字节数。接着判断文件是否被正常打开,最后是读取源文件的内容然后遍历到新文件中,关闭打开的文件。

int main(int argc, char** argv)

(先说结论,argc表示一共有多少个参数,argv表示每个参数对应的内容)

重点讲一下这个,毕竟我也是第一次见到main函数中还含有参数。

参数int argc,char** argv

它是一个整形的数据类型,它表示的是参数的个数,如何去理解呢?请往下看:

cs 复制代码
./a.out hello world test

比如说我在终端上运行这个命令,那么argc就应该等于4。为什么等于4呢。结合上面的结论就可以知道。argv0 = "./a.out"为第一个参数;argv1 = "hello"为第二个参数;argv2 = "world"为第三个参数;argv3 = "test"为第四个参数。所以argc等于4是这么来的。

cs 复制代码
sudo ./build/copy 1.txt 2.txt

上面这个是我在终端上运行的命令,按照刚刚来的话那argc就等于3。argv0 = "./build/copy";argv1 = "1.txt";argv2 = "2.txt"。

提出问题

为什么要在main函数中传入参数?核心原因就是使程序具有"通用性"和"动态性",如果不这样写的话,就需要每次都进入代码中修改文件名。就像前面学习Makefile一样,都是为了方便,统一管理。

相关推荐
爱写代码的森6 小时前
鸿蒙三方库 | harmony-utils之ImageUtil图片保存到本地详解
服务器·华为·harmonyos·鸿蒙·huawei
大耳朵-小飞象8 小时前
电力安全运维的智能密码:BACS如何破解设备全生命周期管理难题,让电网安全“看得见、管得住”?
运维·安全·智慧城市·能耗系统·楼宇智控·未来生活
极客侃科技9 小时前
制造企业 MES/APS 选型:SAP PP/DS 集成、ERP-MES 边界划分与一体化架构要点
运维·架构·制造
HLC++9 小时前
Linux的进程间通信
android·linux·服务器
华清远见IT开放实验室11 小时前
实验室建设案例 | 石家庄科技信息职业学院嵌入式实验室——从底层硬件到系统应用,一所应用型高校的嵌入式人才培养这样落地
linux·arm开发·stm32·嵌入式硬件·高校·实验室建设
白露与泡影11 小时前
Arthas 实战指南:从方法耗时定位到 JVM 变量热修改
服务器·jvm·c#
神奇霸王龙12 小时前
Claude Code屠榜:MiMo与Grok紧追Codex
服务器·网络·人工智能·gpt·ai·ai编程
Web极客码12 小时前
WordPress SEO优化:提升网站排名的13个关键步骤
服务器·seo·wordpress
生活爱好者!12 小时前
我把NAS当作下载机,docker一键部署qb
运维·docker·容器
FrameNotWork13 小时前
HarmonyOS 6.0 LocalStorage页面级存储
华为·交互·harmonyos