六、文件IO——fcntl 函數 和 ioctl 函數
阿新 • • 發佈:2018-05-15
read event 情況 har 屬性 並且 enc 名稱 lock
6.1 fcntl 函數
6.1.1 函數介紹
1 #include <unistd.h> 2 #include <fcntl.h> 3 int fcntl(int fd, int cmd); 4 int fcntl(int fd, int cmd, long arg); 5 int fcntl(int fd, int cmd, struct flock * lock);
- 函數說明:fcntl()用來操作文件描述詞的一些特性。
- 函數功能:可以改變已經打開文件的性質
- 參數說明
- @fd:代表欲設置的文件描述符
- @cmd:代表欲操作的指令。有以下幾種情況:
- F_DUPFD:用來查找大於或等於參數 arg 的最小且仍未使用的文件描述符,並且復制參數 fd 的文件描述符。執行成功則返回新復制的文件描述符。請參考dup2()。復制文件描述符,新的文件描述符作為函數返回值返回
- F_GETFD:獲取文件描述符,通過第三個參數設置
- F_SETFD:設置文件描述符,通過第三個參數設置
- F_GETFL/F_SETFL:
- 取得/設置文件狀態標誌,通過第三個參數設置
- 可以更改的幾個標誌是:O_APPEND、O_NONBLOCK、SYNC、O_ASYNC(O_RDONLY、O_WRONLY和O_RDWR不適用)
- F_GETLK 取得文件鎖定的狀態。
- F_SETLK 設置文件鎖定的狀態。此時flcok 結構的l_type 值必須是F_RDLCK、F_WRLCK或F_UNLCK。如果無法建立鎖定,則返回-1,錯誤代碼為EACCES 或EAGAIN。
- F_SETLKW F_SETLK 作用相同,但是無法建立鎖定時,此調用會一直等到鎖定動作成功為止。若在等待鎖定的過程中被信號中斷時,會立即返回-1,錯誤代碼為EINTR。
- @參數lock指針為flock 結構指針,定義在下面。
- 返回值:
- 成功則返回0,若有錯誤則返回-1,錯誤原因存於errno。
- 常見的功能:
- 復制一個現存的描述符,新文件描述符作為函數返回值(cmd = F_DUPFD)
- 獲得/設置文件描述符標誌(cmd = F_GETFD 或 F_SETFD)
- 獲得/設置文件狀態標誌(cmd = F_GETFL 或 F_SETFL)
- 獲得/設置文件鎖(cmd = F_SETLK、cmd= F_GETLK、F_SETLKW)
- 第三個參數為 struct flock 結構體,定義如下
1 struct flcok 2 { 3 shortint l_type; /* 鎖定的狀態*/ 4 short int l_whence;/*決定l_start位置*/ 5 off_t l_start; /*鎖定區域的開頭位置*/ 6 off_t l_len; /*鎖定區域的大小*/ 7 pid_t l_pid; /*鎖定動作的進程*/ 8 };
- l_type 有三種狀態:
- F_RDLCK 建立一個供讀取用的鎖定
- F_WRLCK 建立一個供寫入用的鎖定
- F_UNLCK 刪除之前建立的鎖定
- l_whence 也有三種方式:
- SEEK_SET 以文件開頭為鎖定的起始位置。
- SEEK_CUR 以目前文件讀寫位置為鎖定的起始位置
- SEEK_END 以文件結尾為鎖定的起始位置。
6.1.2 例子
文件狀態標誌設置
io.h
1 #ifndef __IO_H__ 2 #define __IO_H__ 3 4 extern void copy(int fdin, int fdout); 5 6 extern void set_fl(int fd, int flag); 7 extern void clr_fl(int fd, int flag); 8 #endif
io.c
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <fcntl.h> 4 #include <unistd.h> 5 #include "io.h" 6 #include <string.h> 7 #include <errno.h> 8 #include <stdlib.h> 9 #include <stdio.h> 10 #include <fcntl.h> 11 12 13 #define BUFFER_LEN 1024 14 15 /* 文件的讀寫拷貝 */ 16 void copy(int fdin, int fdout) 17 { 18 char buff[BUFFER_LEN]; 19 ssize_t size; 20 21 // printf("file length: %ld\n", lseek(fdin, 0L, SEEK_END));//將文件定位到文件尾部,偏移量為0L 22 // lseek(fdin, 0L, SEEK_SET);// 定位到文件開頭 23 24 while((size = read(fdin, buff, BUFFER_LEN)) > 0) { //從 fdin 中讀取 BUFFER_LEN 個字節存放入 buff 中 25 // printf("current: %ld\n", lseek(fdin, 0L, SEEK_CUR)); 26 27 if(write(fdout, buff, size) != size) { 28 fprintf(stderr, "write error: %s\n", strerror(errno)); 29 exit(1); 30 } 31 } 32 if(size < 0) { 33 fprintf(stderr, "read error:%s\n", strerror(errno)); 34 exit(1); // 相當於 return 1; 35 } 36 } 37 38 39 void set_fl(int fd, int flag) 40 { 41 int val; 42 43 //獲得原來的文件狀態標誌 44 val = fcntl(fd, F_GETFL); 45 if(val < 0) { 46 perror("fcntl error"); 47 } 48 49 //增加新的文件狀態標誌 50 val |= flag; 51 52 //重新設置文件狀態標誌(val 為新的文件狀態標誌) 53 if(fcntl(fd, F_SETFL, val) < 0) { 54 perror("fcntl error"); 55 } 56 } 57 58 void clr_fl(int fd, int flag) 59 { 60 int val; 61 62 val = fcntl(fd, F_GETFL); 63 if(val < 0) { 64 perror("fcntl error"); 65 } 66 //清除指定的文件狀態標誌(設置為0) 67 val &= ~flag; 68 if(fcntl(fd, F_SETFL, val) < 0) { 69 perror("fcntl error"); 70 } 71 }
file_append.c
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <fcntl.h> 4 #include <unistd.h> 5 #include <string.h> 6 #include <errno.h> 7 #include <stdlib.h> 8 #include <stdio.h> 9 #include <fcntl.h> 10 #include "io.h" 11 12 int main(int argc, char *argv[]) 13 { 14 if(argc < 3) { 15 fprintf(stderr, "usage: %s content destfile\n", argv[0]); 16 exit(1); 17 } 18 19 int fd; 20 int ret; 21 size_t size; 22 23 fd = open(argv[2], O_WRONLY); 24 25 //設置追加的文件狀態標誌 26 set_fl(fd, O_APPEND); 27 28 //清除追加文件狀態標誌 29 //clr_fl(fd, O_APPEND); 30 /* 31 fd = open(argv[2], O_WRONLY | O_APPEND); 32 if(fd < 0){ 33 perror("open error"); 34 exit(1); 35 } 36 37 */ 38 /* 39 //定位到文件尾部 40 ret = lseek(fd, 0L, SEEK_END); 41 if(ret == -1) { 42 perror("lseek error"); 43 close(fd); 44 exit(1); 45 } 46 */ 47 sleep(10); //睡眠 10s 48 49 //往文件中追加內容 50 size = strlen(argv[1]) * sizeof(char); 51 if(write(fd, argv[1], size) != size) { 52 perror("write error"); 53 close(fd); 54 exit(1); 55 } 56 57 return 0; 58 }
編譯調試與 file_append 例子中相同
6.2 ioctl函數---io設備控制函數
1 #include <unistd.h> 2 #include <sys/ioctl.h> 3 int ioctl(int fd, int cmd, …)
- 函數說明:
- ioctl是設備驅動程序中對設備的I/O通道進行管理的函數。所謂對I/O通道進行管理,就是對設備的一些特性進行控制,例如串口的傳輸波特率、馬達的轉速等等。
- ioctl函數是文件結構中的一個屬性分量,就是說如果你的驅動程序提供了對ioctl的支持,用戶就能在用戶程序中使用ioctl函數控制設備的I/O通道。
- 此函數可以說是 I/O操作的雜物箱。不能用前面說的函數表示的 I/O 操作通常都能用 ioctl 表示。
- 終端 I/O 是 ioctl 的最大使用方面,主要用於設備 I/O 控制
- 函數功能:
- 控制I/O設備 ,提供了一種獲得設備信息和向設備發送控制參數的手段。
- 用於向設備發控制和配置命令 ,有些命令需要控制參數,這些數據是不能用read / write 讀寫的,稱為Out-of-band數據。
- 也就是說,read / write 讀寫的數據是in-band數據,是I/O操作的主體,而ioctl 命令傳送的是控制信息,其中的數據是輔助的數據。
- 參數說明:
- @fd :就是用戶程序打開設備時使用open函數返回的文件標示符,
- @cmd :就是用戶程序對設備的控制命令,
- @.... : 省略號,那是一些補充參數,即可變參數列表,一般最多一個,有或沒有是和cmd的意義相關的。
- 返回值:成功為0,出錯為-1
6.2.2 例子
從鍵盤 IO 設備中,讀取鍵盤的數據
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <fcntl.h> 4 #include <unistd.h> 5 #include <string.h> 6 #include <errno.h> 7 #include <stdlib.h> 8 #include <stdio.h> 9 #include <fcntl.h> 10 #include <sys/ioctl.h> 11 #include <linux/input.h> 12 13 int main(int argc, const char *argv[]) 14 { 15 int fd = -1; 16 char name[256] = "Unknown"; 17 struct input_event event;//事件源 18 int ret = 0; 19 20 if((fd = open("/dev/input/event1", O_RDONLY)) < 0) { 21 perror("open error"); 22 exit(1); 23 } 24 25 //EVIOCGNAME 宏的作用是獲得 IO 設備的名稱 26 if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) { 27 perror("evdev ioctl error\n"); 28 exit(1); 29 } 30 31 printf("The device says its name is %s\n", name); 32 33 //讀寫打開的設備文件 34 while(1) { 35 ret = read(fd, &event, sizeof(event)); 36 if(ret < 0) { 37 perror("read event error\n"); 38 } 39 40 if(EV_KEY == event.type) { 41 //如果事件是一個按鍵碼 42 printf("key code is %d\n", event.code); 43 44 if(event.code == 16) { 45 //按 q 退出此應用程序 46 break; 47 } 48 } 49 } 50 51 close(fd); 52 53 return 0; 54 }
六、文件IO——fcntl 函數 和 ioctl 函數