在linux下,一切皆文件。linux
文件描述符用於操做文件。shell
從shell中運行一個進程,默認會有3個文件描述符存在(0、1、2);)0表示標準輸入,1表示標準輸出,2表示標準錯誤。函數
一個進程當前有哪些打開的文件描述符能夠經過/proc/進程ID/fd目錄查看。測試
一、 dup函數spa
#include <unistd.h>
int dup(int oldfd);
功能:複製一個文件描述符code
返回值:成功則返回一個新的文件描述符,失敗則返回-1。blog
當複製成功時,返回值是當前進程可用的最小的文件描述符,返回的新文件描述符和參數oldfd指向同一個文件,繼承
如有錯誤則返回-1,錯誤代碼存於errno中。索引
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
int main() { int fd = open("a.txt", O_RDWR | O_CREAT); if(fd == -1) { perror("open"); exit(1); }
printf("file open fd = %d\n", fd); // 找到進程文件描述表中第一個可用的文件描述符A // 將參數指定的文件描述符B複製給A,並返回A
int fd2 = dup(fd); if(fd2 == -1) { perror("dup"); exit(1); } printf("dup fd = %d\n", fd2); char* buf = "hello"; char* buf1 = " world\n"; write(fd, buf, strlen(buf)); write(fd2, buf1, strlen(buf1)); close(fd); return 0; }
root@lmw-virtual-machine:/home/lmw/桌面/linux_system_program/dup2_dup# ./ab file open fd = 3 dup fd = 4 root@lmw-virtual-machine:/home/lmw/桌面/linux_system_program/dup2_dup# cat a.txt hello world root@lmw-virtual-machine:/home/lmw/桌面/linux_system_program/dup2_dup#
2. dup2函數進程
#include <unistd.h>
int dup2(int oldfd, int newfd);
功能:複製一個文件描述符,且指定文件描述符newfd爲oldfd的複製版本。
返回值:成功返回newfd,失敗返回-1。
dup2函數成功返回時,目標描述符(函數第二個參數,newfd)將變成源描述符(函數第一個參數,oldfd)的複製品,
即,兩個文件描述符如今都指向同一個文件,而且是源描述符指向的文件。
如有錯誤則返回-1,錯誤代碼存於errno中。
dup2詳解:
①、若是newfd已經打開,則先將其關閉,再指定文件描述符newfd爲oldfd的複製版本。
②、若是newfd等於oldfd,則dup2直接返回newfd, 而不關閉它。
//測試dup2函數 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main() { int fd = open("b.txt", O_RDWR | O_CREAT); if(fd == -1) { perror("open"); exit(1); } int fd1 = open("a.txt", O_RDWR); if(fd1 == -1) { perror("open"); exit(1); } printf("fd = %d\n", fd); printf("fd1 = %d\n", fd1); int curfd = dup2(fd, fd1); //讓fd1和fd同時指向b.txt if(curfd == -1) { perror("dup2"); exit(1); } printf("current fd = %d\n", curfd); char* buf = "hello\n"; char* buf1 = "world!\n"; write(fd, buf, strlen(buf)); write(fd1, buf1 , strlen(buf1)); close(fd); close(fd1); return 0; }
編譯運行:
root@lmw-virtual-machine:/home/lmw/桌面/linux_system_program/dup2_dup# gcc dup2.c -o ab root@lmw-virtual-machine:/home/lmw/桌面/linux_system_program/dup2_dup# ./ab fd = 3 fd1 = 4 current fd = 4 root@lmw-virtual-machine:/home/lmw/桌面/linux_system_program/dup2_dup# cat b.txt hello world! root@lmw-virtual-machine:/home/lmw/桌面/linux_system_program/dup2_dup# cat a.txt hello world root@lmw-virtual-machine:/home/lmw/桌面/linux_system_program/dup2_dup#
實驗先後,a.txt的內容未發生改變,同時根據實驗後b.txt的內容,證明了dup2函數功能的有效性。
注意: 經過dup和dup2建立的文件描述符,不繼承原文件描述符的close-on-exec和non-blocking屬性。
細節補充:
int dup(int oldfd);
dup函數:函數執行成功時,新獲得的文件描述符和oldfd,共享文件偏移量和文件狀態。
共享偏移量測試代碼:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> // off_t lseek(int fd, off_t offset, int whence);第二個參數是偏移量,第三個參數是起始地址,要注意區分 int main(int argc, char const *argv[]) { int fd = open("b.txt", O_RDONLY); //1. 先複製fd,獲得copyfd int copyFd = dup(fd); //2. 而後對fd、copyfd中的一個文件描述符進行操做,觀察另外一個文件描述符的變化 //置fd對應的當前文件數據索引偏移量到文件尾 unsigned long offset = lseek(fd, 0, SEEK_END); // 打印偏移量 printf("fd = %d , 距離文件頭的偏移量:%ld\n", fd, offset); //打印copyFd的文件數據索引偏移量 printf("copyFd = %d , 距離文件頭的偏移量:%ld\n", copyFd, lseek(copyFd, 0, SEEK_CUR)); return 0; }
編譯運行:
root@lmw-virtual-machine:/home/lmw/桌面/linux_system_program/dup2_dup# gcc dup_2.c -o ab root@lmw-virtual-machine:/home/lmw/桌面/linux_system_program/dup2_dup# ./ab fd = 3 , 距離文件頭的偏移量:14 copyFd = 4 , 距離文件頭的偏移量:14 root@lmw-virtual-machine:/home/lmw/桌面/linux_system_program/dup2_dup# root@lmw-virtual-machine:/home/lmw/桌面/linux_system_program/dup2_dup#
現象和結論:使用了dup,操縱fd的文件數據索引偏移,致使copyfd的偏移量也跟着移動到了文件末尾。
int dup2(int oldfd, int newfd);
dup2函數:函數執行成功時,新獲得的文件描述符newfd和oldfd,共享文件偏移量和文件狀態。
共享偏移量測試代碼:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main(int argc, char const *argv[]) { int fd = open("b.txt", O_RDONLY); int newfd; //1. 獲取有效的newfd newfd = dup2(fd, 14); //2. 而後對fd、newfd中的一個文件描述符進行操做,觀察另外一個文件描述符的變化 //置fd對應的文件數據索引偏移到文件尾 unsigned long offset = lseek(fd, 0, SEEK_END); // 打印偏移量 printf("fd = %d , 距離文件頭的偏移量:%ld\n", fd, offset); //打印newfd的文件數據索引偏移 printf("newfd = %d , 距離文件頭的偏移量:%ld\n", newfd, lseek(newfd, 0, SEEK_CUR)); return 0; }
編譯運行:
root@lmw-virtual-machine:/home/lmw/桌面/linux_system_program/dup2_dup# gcc dup_2.c -o ab root@lmw-virtual-machine:/home/lmw/桌面/linux_system_program/dup2_dup# ./ab fd = 3 , 距離文件頭的偏移量:14 newfd = 14 , 距離文件頭的偏移量:14 root@lmw-virtual-machine:/home/lmw/桌面/linux_system_program/dup2_dup#
現象和結論:使用了dup2,操縱fd的文件數據索引偏移,致使newfd的偏移量也跟着移動到了文件末尾。
.