天天看点

Linux 文件IO

本系列文章节选自本人所著《Linux下C语言应用编程》。

本系列文章,所需代码请从以下地址下载:

http://download.csdn.net/download/scyangzhu/5129027

1.1.1   ioctl

ioctl 函数是I / O操作的杂物箱。不能用本章中其他函数表示的I / O操作通常都能用ioctl表示。终端I / O是ioctl 的最大使用方面,主要用于设备的I / O控制。例如:串口线上传送的数据通过read、write来操作,而串口的波特率、校验位、停止位可以通过ioctl来设置。再例如,使用ioctl来控制光驱的弹出操作等。

#include <sys/ioctl.h>

int ioctl(int fd, int cmd, . . . ) ;

功能:要求设备完成某种操作

返回:若出错则为- 1,若成功则为其他值。

参数:

fd:要操控的设备的文件描述符

cmd:要求设备完成的操作。一般会是针对该设备的头文件中定义的宏

第3个参数:针对cmd操作的参数

使用范例(使用ioctl控制CDROM):

ioctl.c

 1 #include <linux/cdrom.h>

 2 #include <stdio.h>

 3 #include <stdlib.h>

 4 #include <fcntl.h>

 5

 6 int main(void)

 7 {

 8         int fd =open("/dev/cdrom", O_RDONLY | O_NONBLOCK);

 14 //     ioctl(fd, CDROM_LOCKDOOR, 0);

 15        if (!ioctl(fd, CDROMEJECT, NULL)) {

 16                 printf("eject cdromsucceed\n");

 17        } else {

 18                 printf("eject cdromfailed\n");

 19        }

 20

 29        return 0;

 30 }

运行结果:

[[email protected] chap02]$ sudo./ioctl

eject cdrom succeed

代码分析:

1行包含的头文件linux/cdrom.h中,定义了光驱这种设备所支持的操作的宏

8行调用open打开光驱,得到对应光驱的文件描述符。由于open光驱时,可能光驱中没有光盘,因此需要使用O_NONBLOCK选项,否则open会失败

15行调用ioctl,向光驱发出CDROMEJECT命令(弹出光盘命令)。用户可看到光盘被成功弹出

1.1.2   select

read函数可以监控1个文件描述符(例如:键盘)是否有输入,当键盘没有输入时,read将阻塞,直到用户从键盘输入数据,read成功返回。用相同的方法可以监控鼠标是否有输入。但要同时监控鼠标和键盘是否有输入,这个方法就无能为力了。如下面程序所示:

1 fd = open(“/dev/input/mice”,O_RDONLY);  // /dev/input/mice是鼠标的设备文件

2 read(0, buf, 100);

3 read(fd, buf, 100);

这是因为,当read 键盘时若无输入,则程序阻塞在第2行,此时即使鼠标有输入,程序也没有机会执行第3行去获得鼠标的输入。

这种情况下,需要使用select同时监控多个文件描述符

#include <sys/select.h>

intselect(int maxfd, fd_set *readset, fd_set *writeset, fd_set *exceptset, conststruct timeval *timeout)

功能:同时监控多个文件描述符上是否有输入、输出、错误

参数:

maxfd:表示要检测的描述符个数,因此其值应为最大描述符+1

readset:被监控是否有输入的文件描述符集。不监控时,设为NULL

writeset:被监控是否可以输出的文件描述符集。不监控时,设为NULL

exceptset:被监控是否有错误产生的文件描述符集。不监控时,设为NULL

timeval:监控超时时间。设置为NULL,表示一直阻塞到有文件描述符被监控到有指定变化

返回值:失败,返回-1;成功,返回readset 、writeset、exceptset集中所有有指定变化的文件描述符的数目(若是因超时而返回,返回值为0)。

注:readset 、writeset 、exceptset3 个描述符集指针均是值- 结果参数。调用时,被监控描述字相应位需置1;返回时未就绪描述字相应位会被清0,而就绪描述字相应位会被置1

以下几个系统定义的宏,会与select配套使用

FD_ZERO(&rset):清0文件描述符集rset所有位

FD_SET(4,&rset):设置文件描述符集rset的bit4

FD_CLR(fileno(stdin),&rset):清0文件描述符集rset的bit0

FD_ISSET(socketfd,&rset):若文件描述符集rset中对应socketfd的位置1,返回真;反之,返回假

使用范例(同时监控键盘和鼠标是否有输入):

select.c

 1 #include <stdio.h>

 3 #include <sys/select.h>

 4 #include <fcntl.h>

 5 #include<unistd.h>

  6

  7 #define MAXNUM 100

  8

 9 int main(void)

 10 {      

 11        fd_set rfds;

 12        struct timeval tv;

 13        int retval, fd;

 14        char buf[MAXNUM];

 15        

 16        fd = open("/dev/input/mice", O_RDONLY);

 21        while (1) {

 22                 FD_ZERO(&rfds);

 23                 FD_SET(0, &rfds);

 24                 FD_SET(fd,&rfds);

 25                 tv.tv_sec = 5;

 26                 tv.tv_usec = 0;

 27                

 28                 retval = select(fd + 1,&rfds, NULL, NULL, &tv);

 29                 if (retval < 0)

 30                        printf("error\n");

 31                 if (retval == 0)

 32                         printf("No datawithin 5 seconds\n");

 33                 if (retval > 0) {

 34                         if (FD_ISSET(0,&rfds)) {

 35                               printf("Data is available from keyboard now\n");

 36                                read(0, buf,MAXNUM);

 37                         }

 38                         if (FD_ISSET(fd,&rfds)) {

 39                                printf("Data is available from mouse now\n");

 40                                 read(fd, buf,MAXNUM);

 41                         }

 42                 }

 43        }

 44        return 0;

 45 }

执行结果:

1 [[email protected] chap02]$  sudo ./select

2 a  (此处,从键盘输入a和回车)

3 Data is available from keyboard now

4 Data is available from mouse now  (此处单击鼠标左键)

5 Data is available from mouse now

6 No data within 5 seconds    (此处一直没有任何操作)

结果分析:

16行打开鼠标对应的文件描述符

22行清空文件描述符集rfds

23-24行将rfds中对应键盘和鼠标的位置1

25-26行设置超时时间

28行调用select同时监控键盘和鼠标是否可读,并设置超时时间为5秒

当用户从键盘输入时,34行结果为真,执行35行打印结果(见执行结果第3行)

当用户单击鼠标时,38行结果为真,执行39行打印结果(见执行结果第4、5行)

当用户在5秒内没有任何操作,将导致28行返回0,从而执行32行打印结果(见执行结果第6行)

特别说明:select以相同方式对待以非阻塞方式和以阻塞方式打开的文件描述符。即:被select监控的文件描述符即使是以非阻塞方式打开的,如果没有实际数据可读,select也将阻塞,而不是返回。

继续阅读