天天看點

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光驅時,可能光驅中沒有CD光牒,是以需要使用O_NONBLOCK選項,否則open會失敗

15行調用ioctl,向光驅發出CDROMEJECT指令(彈出CD光牒指令)。使用者可看到CD光牒被成功彈出

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也将阻塞,而不是傳回。

繼續閱讀