在初級文件IO里面這兩個函數的用法比較復雜,單獨記錄下
fcntl
原型
#include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, ... /* arg */ );
功能
fcntl函數其實是File Control的縮寫,通過fcntl可以設置、或者修改已打開的文件性質。
參數
fd:指向打開文件
cmd:控制命令,通過指定不同的宏來修改fd所指向文件的性質。
F_DUPFD
復制描述符,可用來用來模擬dup和dup2,后面會有例子對此用法進行說明。
使用此參數時,fcntl會從文件描述符資源池中選擇一個文件描述符,該文件描述符≥參數arg。如果arg是0,表示第三個參數用不到。
返回值:返回復制后的新文件描述
F_GETFL、F_SETFL
獲取、設置文件狀態標志,比如在open時沒有指定O_APPEND,可以使用fcntl函數來補設。
返回值:返回文件的狀態
什么時候需要fcntl來補設?
當文件描述符不是你自己open得到,而是調用別人給的函數,別人的函數去open某個文件,然后再將文件描述符返回給你用,在這種情況下,我們是沒辦法去修改被人的函數,在他調用的open函數里補加文件狀態標志。此時就可以使用fcntl來補設了,使用fcntl補設時,你只需要知道文件描述符即可。
F_GETFD、F_SETFD
讀取、設置文件描述標識
F_GETOWN、F_SETOWN
F_GETLK 或 F_SETLK 或 F_SETLKW
返回值
調用成功:返回值視具體參數而定
調用失敗:返回-1,並把錯誤號設置給errno。
代碼演示
fcntl 模擬dup和dup2
1 #include <stdio.h> 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include <fcntl.h> 5 #include <unistd.h> 6 #include <errno.h> 7 8 int main(void) 9 { 10 int fd = 0; 11 12 fd = open("./file.txt", O_RDWR); 13 if(-1 == fd) 14 { 15 printf("open fail: %d\n", errno); 16 return 0; 17 } 18 19 /* 模擬dup */ 20 //close(1); 21 //dup(fd); 22 23 //close(1); 24 //fcntl(fd, F_DUPFD, 0); 25 26 /* 模擬dup2 */ 27 //dup2(fd, 1); 28 close(1); 29 fcntl(fd, F_DUPFD, 1); 30 31 printf("hello world!!\n"); 32 33 return 0; 34 }
雖然fcntl()可以模擬文件描述符復制,但實際應用中還是使用dup、dup2
fcntl補設O_APPEND文件狀態標志
1 #include <stdio.h> 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include <fcntl.h> 5 #include <unistd.h> 6 #include <errno.h> 7 8 int open_fun1(void) 9 { 10 int fd = open("./file.txt", O_RDWR); 11 if(-1 == fd) 12 { 13 printf("open fail: %d\n", errno); 14 return 0; 15 } 16 return fd; 17 } 18 19 int open_fun2(void) 20 { 21 int fd = open("./file.txt", O_RDWR); 22 if(-1 == fd) 23 { 24 printf("open fail: %d\n", errno); 25 return 0; 26 } 27 return fd; 28 } 29 30 int main(void) 31 { 32 int fd1 = 0; 33 int fd2 = 0; 34 int flag = 0; 35 36 fd1 = open_fun1(); 37 fd2 = open_fun2(); 38 39 /* 直接制定F_SETFL時,會直接使用新的標志,去修改掉就的標志 40 返回的是新設置的標志 41 */ 42 flag = O_WRONLY|O_TRUNC|O_APPEND; 43 fcntl(fd1, F_SETFL, flag); 44 45 /* 保留原有標志,然后在原有標志的基礎上,疊加新標志 */ 46 flag = fcntl(fd2, F_GETFL, 0);//獲取原有標志 47 flag = flag | O_TRUNC | O_APPEND;//疊加 48 fcntl(fd2, F_SETFL, flag); //設置回去 49 50 while(1) 51 { 52 write(fd1, "hello\n", 6); 53 sleep(1); 54 write(fd2, "world\n", 6); 55 } 56 57 return 0; 58 }
ioctl
XXXX