博客
关于我
设备和文件IO
阅读量:344 次
发布时间:2019-03-04

本文共 3422 字,大约阅读时间需要 11 分钟。

设备与文件管理

Linux系统将硬件设备与文件统一管理,使得设备的操作方式与文件操作相似,从而实现了设备的无关性。所有设备都可看作特殊文件,通过文件系统对设备进行管理,隐藏了硬件设备的具体特性。

设备管理特点

①每个设备对应文件系统中的索引节点,具有唯一的文件名。

②应用程序通常通过系统调用open()打开设备文件,与目标设备建立连接。

③设备的使用方式类似于文件的读写操作。

④设备驱动程序是系统内核的一部分,必须遵循标准接口,为内核或子系统提供服务。

⑤设备驱动程序可利用内核服务,如内存分配等功能。


设备工作原理

Linux系统通过虚拟文件系统的方式,将硬件设备抽象为文件。用户应用程序可以通过文件操作的方式进行设备操作,内核负责将操作转化为实际的硬件操作。这种机制实现了设备的透明化管理。


设备分类

按设备属性可分为以下几类:

1. 按属主关系:系统设备(如显卡、网卡)与用户设备(如存储设备、终端设备)

2. 按设备信息交换单位:字符设备(如终端、网络)与块设备(如硬盘、分区)

3. 按共享属性:独享设备与共享设备


Linux设备操作

Linux系统提供了丰富的接口供应用程序与设备交互。用户编程接口包括设备特定的函数库,而系统调用则为设备操作提供了更底层的接口。


系统调用

系统调用是操作系统为用户提供的特殊接口,通过软中断将用户空间的请求提交给内核,完成后将结果返回用户空间。系统调用让程序能够进入内核空间执行特定操作。

系统调用与系统API的区别

系统API主要通过C库libc实现,程序员常用这些接口与内核交互。系统命令则是通过可执行文件与内核交互,外壳程序则由系统命令和SHELL脚本组合而成。


函数库调用与系统调用

函数库调用 系统调用
所有ANSI编译器版本中的C库函数一致 各操作系统的系统调用不同
调用函数库中的特定函数 调用系统内核服务
用户程序与系统相连 操作系统入口函数
用户地址空间执行 内核地址空间执行
用户时间 系统时间
过程调用,效率高 上下文切换,效率低
约300个C函数 约90个系统调用
systemfprintf chdirfork

C库文件操作函数

函数名 功能
fopen() 打开文件
fclose() 关闭文件
fputc() 写入文件
fgetc() 读取文件
fread() 读取文件数据
fwrite() 写入文件数据
fseek() 定位文件位置
fprintf() 格式化输出
fscanf() 格式化输入
feof() 判断是否到达文件末尾
ferror() 判断文件操作是否出错
rewind() 文件位置重置
remove() 删除文件
fflush() 刷新文件缓冲区

文件描述符fd

每个进程维护一个文件描述符表,记录打开的文件信息。内核禁止直接访问文件描述符表,返回文件描述符ID(File Description ID)给用户程序。

系统预留三个特殊文件描述符:0(标准输入)、1(标准输出)、2(标准错误流)。这些描述符在进程加载时自动开放。

文件描述符的使用具有资源限制,可通过ulimit –n查看。


系统函数

open系统调用

open函数用于打开或创建文件,支持多种模式和权限设置:

参数:

- path:文件路径- flags:文件打开模式(如
O_RDONLY
O_WRONLY
O_RDWR等)- mode:文件权限掩码(可选)

返回值:

  • 成功返回文件描述符
  • 失败返回-1

常用模式:

-
O_RDONLY:只读-
O_WRONLY:只写-
O_RDWR:读写-
O_APPEND:追加模式-
O_CREAT:创建文件(需提供mode参数)-
O_EXCL:创建时如果文件已存在则失败-
O_TRUNC:截断文件

权限掩码由S_IRUSRS_IWUSR等宏定义组成,支持灵活的权限设置。

示例:

#include 
#include
#include
void main() { int outfd = 0; if ((outfd = open("test", O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU)) == -1) { perror("fail to open file"); return -1; } // 后续操作 close(outfd);}

close系统调用

close函数用于关闭已打开的文件或设备:

#include 
int close(int fd);

read系统调用

read函数用于从文件或设备读取数据:

#include 
int read(int fd, void *buf, size_t nbytes);

write系统调用

write函数用于向文件或设备写入数据:

#include 
int write(int fd, const void *buf, size_t nbytes);

lseek系统调用

lseek函数用于移动文件读写位置:

#include 
#include
off_t lseek(int fd, off_t offset, int base);

fcntl系统调用

fcntl函数用于管理文件锁:

#include 
#include
int fcntl(int fd, int cmd, struct flock *lock);

锁信息结构体struct flock包含:

struct flock {    short l_type;   /* 锁类型:F_RDLCK、F_WRLCK、F_UNLCK */    short l_whence; /* 偏移基点:SEEK_SET、SEEK_CUR、SEEK_END */    off_t l_start;  /* 锁的起始偏移量 */    off_t l_len;    /* 锁的长度 */    pid_t l_pid;    /* 锁所属进程ID */};

示例:

#include 
#include
int main() { int fd; struct flock lock; if ((fd = open("test", O_RDWR | O_CREAT, S_IRWXU)) == -1) { printf("open file error"); return -1; } memset(&lock, 0, sizeof(struct flock)); lock.l_start = SEEK_SET; lock.l_whence = SEEK_SET; lock.l_len = 0; if (fcntl(fd, F_GETLK, &lock) == 0) { if (lock.l_type != F_UNLCK) { printf("lock cannot be set in fd"); } else { lock.l_type = F_WRLCK; if (fcntl(fd, F_SETLK, &lock) == 0) { printf("set write lock success!"); } else { printf("set write lock fail!"); } getchar(); lock.l_type = F_UNLCK; fcntl(fd, F_SETLK, &lock); } } close(fd); return 0;}

转载地址:http://odah.baihongyu.com/

你可能感兴趣的文章
Vue踩坑笔记 - 关于vue静态资源引入的问题
查看>>
Netty工作笔记0025---SocketChannel API
查看>>
Netty工作笔记0027---NIO 网络编程应用--群聊系统2--服务器编写2
查看>>
Netty工作笔记0050---Netty核心模块1
查看>>
Netty工作笔记0057---Netty群聊系统服务端
查看>>
Netty工作笔记0060---Tcp长连接和短连接_Http长连接和短连接_UDP长连接和短连接
查看>>
Netty工作笔记0063---WebSocket长连接开发2
查看>>
Netty工作笔记0070---Protobuf使用案例Codec使用
查看>>
Netty工作笔记0077---handler链调用机制实例4
查看>>
Netty工作笔记0084---通过自定义协议解决粘包拆包问题2
查看>>
Netty工作笔记0085---TCP粘包拆包内容梳理
查看>>
Netty常用组件一
查看>>
Netty常见组件二
查看>>
netty底层源码探究:启动流程;EventLoop中的selector、线程、任务队列;监听处理accept、read事件流程;
查看>>
Netty心跳检测机制
查看>>
Netty核心模块组件
查看>>
Netty框架内的宝藏:ByteBuf
查看>>
Netty框架的服务端开发中创建EventLoopGroup对象时线程数量源码解析
查看>>
Netty源码—2.Reactor线程模型一
查看>>
Netty源码—3.Reactor线程模型三
查看>>