- 這篇博客很長,希望你能看完,是我自己對文件描述符的一些理解,希望能幫助到你
文件描述符
什麼是文件描述符
- 文件描述符是操作系統在進行進程文件管理時,所引入的一種管理方法,這種管理方法是 先描述文件的一系列信息,然後再通過這個文件描述符,進行文件的一些列讀寫操作
文件描述符在進程中是如何存儲的
- 在進程的PCB中,有專門寸出文件描述符的位置。
- 在PCB中,有一個*files 的指針,這個指針指向一個名叫 files_struct 的指針數組,這裏這個指針數組裏存儲的就是指向不同文件的指針,既然是一個數組,那就可以通過下標進行數組元素的訪問,所以,這裏數組的下標的值,就是文件描述符的值。
- 在linux中,一切皆文件,在計算機當中,我們最常接觸的就是標準輸入和標準輸出,還有標準錯誤輸出,這三個在linux中都是以文件的形式存在的,一個進程在開闢的時候,會自動打開這三個文件,存放在 0 1 2 的下標的位置,所以,這三個對應 標準輸入,標準輸出,標準錯誤輸出。
- 我們如果在進程中打開文件的時候,系統就會在這個進程的files_struct中添加進對應的文件的指針,然後返回這個文件指針對應的文件描述符,也就是這個文件的下標。我們在進行文件讀寫操作的時候,如果我們調用的是系統提供的讀寫操作接口的話,就勢必需要使用文件描述符進行操作。(注意,是系統提供的接口,我們在學習語言的時候,其實是通過語言所提供的接口,而非操作系統所提供的接口)這裏我畫了一個圖,幫助你理解系統調用和函數庫調用
- 系統調用接口,正是繞過了語言所提供的庫函數接口,實現了直接面向操作系統的文件操作
文件描述符的一系列操作
- 如果要直接用文件描述符對文件進行讀寫操作的話,就需要調用系統提供的接口,系統提供的接口主要有一下幾個
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int open(const char* pathname, int flag);
int open(const char* pathname, int flag, mode_t mode);
flag:
O_RDONLY:只讀打開
O_WRONLY:只寫打開
O_RDWR :讀寫打開
O_CREAT:若文件不存在,就創建一個文件
O_APPEND:追加寫
注意,以上三個文件,通過‘|’操作符進行組合,達到對應的目的,至於爲什麼是‘|’,你可以理解爲,不同的flag對應不同的 二進制位的1,通過‘|’,可以將這些flag結合起來,達到對應的目的。
返回值:如果成功,返回對應的文件描述符,如果失敗,返回-1
mode就是權限,對應的0000這四個位的權限,一般設置爲0644,如果不進行設置的話,就會隨機生成文件的權限。
#include<unistd.h>
ssize_t write(int fd, const void* buf,size_t count);
ssize_t read(int fd,void *buf,size_t count);
int close(int fd);
off_t lseek(int fd,off_t offset,int whence);
這裏的fd,就是文件對應的文件描述符,可以看到,系統所提供的這幾個接口,都是通過文件描述符,
對文件進行的操作。
在write和read函數中,buf就是緩衝區,write通過緩衝區向文件裏寫數據,read通過緩衝區,
將從文件裏讀到的數據寫入到緩衝區裏,然後帶回來。
write和read 的 count都是一次要讀或寫的期望個數。read的期望數量可以大於你讀到的數據的長度,
讀到文件的結尾就會自動停止,但是寫的話,最多不能超過你所寫的數據的長度。
- 以上就是文件讀寫操作的一些接口,如何使用這些接口,看接下來的代碼
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
int main()
{
char buf[100];
int fd_wr = open("hello.txt",O_WRONLY|O_CREAT,0644);
char *msg = "hello world\n";
if(fd_wr < 0)
{
perror("open file");
}
write(fd_wr,msg,strlen(msg));
close(fd_wr);
int fd_rd = open("hello.txt",O_RDONLY);
if(fd_wr < 0)
{
perror("open file");
}
ssize_t s = read(fd_rd,buf,sizeof(buf));
buf[s] = '\0';
printf("%s",buf);
close(fd_rd);
return 0;
}
- 以上,便是對文件的基本讀寫操作,在操作系統中,如果想對文件進行操作的話,利用的就是文件描述符,如果你在輸出的時候,向標準輸出文件中寫數據的話,系統就會將數據寫到顯示器上,但是,有一點要注意,就是在寫完之後,需要將標準輸出中緩衝區內的數據刷出來,才能直觀的看到所寫入的數據
注意事項
- 文件描述符在分配的時候,並不是按照你打開的文件的順序進行分配的,而是,從目前能分配的最小的文件描述符進行分配,比如說:你如果關閉了這個進程的標準輸入和標準輸出,這兩個文件的文件描述符就會被釋放,然後,再次打開一個新的文件的時候,就會給這個文件分配一個0的文件描述符,佔有標準輸入的文件描述符的位置。
- 在進行文件讀寫操作過後,一定要記得關閉文件。