目录简介通用I/O示例代码copy.c编程思路简介上次我们简单介绍了一下Linux系统编程的环境搭建这篇开始正式走进Linux系统编程的篇章。我们之前介绍操作系统的时候说过无非是为了更好控制硬件才选择开发操作系统人与硬件的交互无非就是人输入硬件输出想要的结果但是我们知道硬件有很多类型什么硬盘网卡终端串口管道等等它们底层硬件各不相同要实现读写操作也十分麻烦而且我们都知道学习Linux首要就是要有一切皆文件的思想以这个思想为基础为了解决硬件差异造成读写不便的问题通用I/O应运而生。通用I/O我们在这篇内主要介绍这几个通用I/O的用法不讲底层具体实现主要为了让大家有一个基本写Linux应用代码框架。通用I/O有五个open()read()write()close()lseek()。下面给出五个函数的参数情况和返回值类型intopen(char*pathname,intflags,mode_tmode);ssize_tread(intfd,void*buffer,size_tcount);ssize_twrite(intfd,void*buffer,size_tcount);intclose(intfd);off_tlseek(intfd;off_toffset;intwhence);是不是看的很迷糊我们一点一点来分析。首先我们可以看到一个变量出现的特别多就是fd这个整形变量fd代表什么呢它叫文件描述符是一个小整数你可以把它当做一个号码牌每次做一件事的时候都需要一个这种号码牌用来处理本次操作信息你的每个进程启动都会自带三个这种号码牌0,1,20代表通用输入1代表通用输出2代表通用错误。此后如果想要做其他事就需要自己申请文件描述符啦。同时有一些我们没见过的变量类型这里简单说明一下比如mode_t就是专门为权限mode设定的变量类型size_t是有符号整形ssize_t是无符号整形off_t则是文件偏移专门的一个整形类型(64位系统一般是long long以操作超大文件)这些变量名不仅方便编程者们记忆而且专门设计的变量名可以有效防止因为整形类型不合适导致范围溢出的现象。好了前置知识讲完了该具体讲讲这几个东西有什么用了首先是它们的基础open它返回一个int类型的fd对就是我们刚刚学到的fd它就是我们申请文件描述符的函数它的作用是根据flag参数打开pathname这个文件如果设置了不存在就创建的话要写权限mode(这里参数比较多一般都是现查的注意参数间用按位或’|隔开呦)这里说到权限其实非常重要它其实有个公式实际权限设置权限-umaskumask就是权限屏蔽数我们知道一个文件权限其实是一个三位八进制数分别代表拥有者拥有者group和陌生人三部分人的权限umask就是在你设置权限的基础上给你屏蔽掉一部分权限如果你是普通用户这个数默认002,如果是root则默认022举个例子你比如权限是666,普通用户创建后它会变成664也就是陌生人只读。总而言之呢这个open就是按照参数要求打开文件并给它一个号码牌readwrite顾名思义了我们要操作刚刚得到的号码牌用这个号码牌叫操作了read就是读count个字节数据存放到缓冲区里write反过来就是从count里写进buffer个字节数据。close呢就是释放掉你申请的号码牌你想想你去餐厅吃完饭牌子总要还给人家嘛。最后再来唠唠这个lseekread和write其实是在这个文件的某个位置进行读写我们叫这个东西是偏移量lseek是设置这个偏移量的offset是偏移量whence是相对位置你可以设置开头结尾或者相对当前位置都可以(这里插入一条知识点如果你偏移量的末尾超出了文件末尾你可以把这个当成溢出吧不过这是合法的呦而且还非常好用我们叫块东西是空洞虽然你创建了它但是在你对它进行读写的时候它不占用磁盘只是逻辑上占用类似于预定吧你后期如果要学到更新代码制作镜像等要留足空间的操作它可是个好帮手)。不过今天我们主要讲前四个的用法下面用一个模拟Linux代码cp的copy.c来简单讲解一下。示例代码copy.c#includefcntl.h#includesys/stat.h#includetlpi_hdr.hdefine BUF_SIZE1024intmain(intargc,char*argv[]){intinputFd,outputFd,openflags;//记录输入输出的fd和flag参数mode_tfilePerms;//文件权限ssize_tnumread;//读取字节数char*buffer[BUF_SIZE];if(argc!3||strcmp(argv[1],--help)0)usageErr(%s old_file new_file\n,argv[0]);inputFdopen(argv[1],RDONLY);//申请被读文件的fdif(inputFd-1)errExit(opening file %s\n,argv[1]);openFlagsO_CREAT|O_WRONLY|O_TRUNC;//参数及权限设置filePermsS_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;/* rw-rw-rw- */outputFdopen(argv[2],openFlags,filePerms);//申请目标文件的fdif(outputFd-1)errExit(opening file %s\n,argv[2]);while((numreadread(inputFd,buffer,BUF_SIZE)0)//写入循环if(write(outputFd,buffer,BUF_SIZE)!numread)fatal(couldnt write whole buffer);if(numread-1)errExit(read);if(close(inputFd)-1)errExit(close input);if(close(outputFd)-1)//释放fderrExit(close output);exit(EXIT_SUCCESS);}注文中用的库下载了TLPI的官方源码读者想要复用代码需自行下载编译https://www.man7.org/tlpi/code/download/tlpi‑240828‑dist.tar.gz接下来我们需要对我们写的代码进行编译gcc copy.c -o copy -ltlpi用以上代码编译后就可以用该代码模拟cp了。编程思路总结一下我们要完成一个功能的代码编写需要有以下步骤1,校验命令行参数2,打开文件并设置权限相关信息3,工作区(主要不同点)4,释放文件资源5,退出这五步其实呀只有第三步是我们需要修改的地方其他东西都是框架性质的东西用多了自然会很熟练了。