我們通過ls查到就是文件屬性,只不過ls只顯示了部分文件屬性。
Table of Contents
10. link,unlink,remove,rename函數
1.涉及到的OS API
stat、fstat、lstat
umask
chmod、fchmod
chown,fchown,lchown
link,unlink,remove,ren
symlink和readlinkchdir、和getcwd
看起來很多,不過每一行都是一組,只要理解其中一個,其它的都很好理解。而且這些函數,都與我們常用的cd、ls、chmod、chown、pwd等命令息息相關
2.文件類型
2.1 文件的7種類型
Linux一切皆文件,文件一共分爲7類分別是 - d c s p l b。
(1)普通文件(regular file:-
文本文件 純二進制文件(機器碼)
(2)目錄文件(director file:d)
目錄是一種特殊的文件,專門用於管理其它文件。
(3)字符設備文件(character special file:c)
字符設備文件,就是字符設備驅動程序,在上層的表現形式。
(4)塊設備文件(block special file:b):對應塊設備(如磁盤等)。
1)塊設備文件,是塊設備驅動程序在上層的表現形式。
2)字符設備與塊設備有什麼區別?
(5)FIFO(fifo:p)
管道文件,用於實現不同進程(程序)之間的通信
(6)套接字文件(socket:s)
專門用於網絡通信的文件。
(7)符號連接(symbolic link:l):
其實就是一種快捷圖標,背後指向了另外一個文件。
2.2 如何判斷文件的類型
(1)ls查看- d c l b s p符號來區分
(2)可以使用file命令來查看
(a)如果查看的是文本文件
(b)如果你查看的是純二進制文件(機器碼)
3、獲取文件屬性的函數,stat、lstat、fstat
ls命令其實就是調用了這三個函數中的lstat來實現的,我們可以調用lstat函數來自己實現一個ls命令。
這三個是兄弟函數,實現的功能相同,只是略微有區別,我們只要先把stat函數搞清楚了,lstat、fstat非常容易理解。
3.1 stat
函數原型
#include <sys/types.h> #include <sys/stat.h> #include <unistd.h> int stat(const char *path, struct stat *buf);
3.2 struct stat結構體
7類文件都有的屬性
專門給塊設備文件用的。
專門給字符設備用的
ls的信息
(1)st_uid 和 st_gid 用戶id 組的組id
(2)st_mode
(a)- :文件類型
(b)rwxrwxr-x:文件權限 (讀寫執行)
文件所屬用戶 所屬組 其他人
(3)將數字形式的st_mode,打印爲-rwxrwxr-x形式
文件類型
12~15 bit用於表示文件類型如何表示文件類型
· 如何取出12~15位的值,然後用於判斷文件的類型
文件權限
(4)如何使用chmod命令修改文件權限(rwx)
(a)方法1:直接使用數字 chmod 777 file.txt
(a)方法2:直接使用rwx來設置
· 例子1:修改所有權限 - chmod a=rw- file.txt
· 例子2:只修改某一組的權限- chmod u=rwx,g=rw-,o=r-- file.txt
· 例子3:只修改組裏面某一位的權限- chmod u+r,g+w,o+x file.txt
3.2 lstat
3.3.fstat
#include <sys/types.h> #include <sys/stat.h> #include <unistd.h> int fstat(int fd, struct stat *buf);
3.5 r w x的含義
1)x對於普通文件來說
如果普通文件存放的只是文字編碼,因爲文字編碼無法被cpu執行,所以普通文件的x沒有太大意義,所以一般的普通文件的x權限一般都是-。
2)x對於目錄的意義?
我們發現目錄都有x,顯然目錄裏面放的並不是機器指令,是不能被執行的,那麼x對於目錄的意義何在呢?
對於目錄的x來說,也被稱爲通過權限,也就是說,如果你的目錄沒有x權限,你是無法通過這個目錄的。
3)x對於其它文件來說,意義不大
4. umask函數
4.0 open函數創建新文件時的一個問題
open函數創建新的文件時,如果指定的是0777滿級權限的話,實際創建文件權限爲0775(rwxrwxr-x)
(1)爲什麼不是滿級權限
因爲被文件權限掩碼做了限制。
(2)怎麼將文件權限掩碼改爲0
使用umask即可。
4.1 函數原型
#include <sys/types.h> #include <sys/stat.h> mode_t umask(mode_t mask);
4.2每一個進程都有一個文件權限掩碼
我的程序,修改只是當前進程的文件權限掩碼,對其它進程的文件權限掩碼無影響。
6. 文件長度st_size
struct stat中的st_size被用來存放文件長度,但只對普通文件目錄、以及符號連接文件有意義。
因爲只有普通文件、目錄、以及符號鏈接文件纔有實際的數據,有數據纔有文件長度
其它的文件在塊設備上只存儲了文件屬性,它們只是掛了一個文件名,以文件的形式進行管理而已,沒有實際的數據,所以對於 這些文件來說,文件大小是沒有意義的。
符號鏈接文件的文件大小
符號鏈接文件就是一個快捷鍵,背後指向了某個文件。
符號鏈接文件的數據,就是所指向文件的文件名,所以它的文件大小指的就是這個名字的字符個數。
7. 文件截斷函數truncate、 ftruncate
open可以指定了O_TRUNC後,文件裏面有數據的話,會將打開的文件截短(清空)爲0,
文件截短函數truncate,它不僅能夠將文件截爲0,還可以把文件截短爲任意長度。
7.1 函數原型
#include <unistd.h> #include <sys/types.h> int truncate(const char *path, off_t length); int ftruncate(int fd, off_t length);
8. 空洞文件
我承諾給你一畝地,但是你又不是馬上就要用滿這一畝地,是一點一點來佔用的,如果我現在一下子把一畝地全部你,
但是你要花費很久時間纔會把地全用上,在你佔滿之前,一直有相當部分空間被閒置不用,顯然非常浪費空間資源。
迅雷等下載文件
比如下載一個1M大小的文件,文件肯定是要花費相當長的時間才能下載完成,如果我直接就開闢一個實際佔用1M空間
的普通文件來放數據的話,在實際下載完數據之前,未裝滿數據的空間都被閒置,會很浪費空間,怎麼辦呢?
解決辦法就是開闢一個1M大小的空洞文件,空洞文件的理論大小是1M,但是並沒有在塊設備上實際給你分配1M的物理空間 而是在下載過程中,每下載一部分數據,再實際開闢一部分空間給你,直到整個文件下完位置。
如何製作空洞文件
truncate、ftrucate製作
文件截短長度 > 文件長度時,多餘的部分就是空洞。
du命令:查看文件在塊設備上,實際佔用的物理空間。
ls查看到的只是文件的理論大小,但是空洞部分並不佔用實際物理存儲空間。
使用lseek製作
將文件讀寫位置調整到文件尾部之後,然後寫點數據,中間空出的部分就是空洞。
9. 文件系統是如何管理文件的
文件系統管理文件的邏輯結構——樹形結構
對於文件系統來說,目錄是非常重要的文件組織節點。
文件在塊設備上是如何存儲的
(1)超級區
負責“塊設備”空間的分配和回收。
(2)inode節點區
1)被劃分爲了一個個相連的,空間大小相同的inode節點空間。
2)每個節點空間被用於存放某個文件的屬性信息,每個節點空間大小是固定的
3)每個節點都有一個節點編號,通過節點編號就可以索引找到inode節點空間。
(3)數據區
存儲數據時,實際上並不是數據有多少個字節,就分配對應多少的字節空間給你,爲了便於物理空間高效管理,往往都是按塊 分配空間的,一塊往往爲4k字節(4*1024)
1)普通文件
2)目錄文件
3)鏈接文件 : 存放的數據很簡單,就是所指向文件的文件名。
文件系統是如何通過“文件路徑名”索引找到文件
1)索引找到普通文件
fd = open("/new/xxx.txt", O_RDWR);
找到數據存放空間的起始地址後,read、write調用驅動讀寫數據時, 塊設備驅動程序”通過這個地址,就能夠實現讀寫。
stat("/new/xxx.txt", ...);
這個函數獲取文件屬性時,也是按照相同的原理來索引的,找到文件的inode節點空間後,就可以將inode節點中的文件屬性讀取出來。
10. link,unlink,remove,rename函數
這幾個函數與ln、rm、mv命令息息相關,因爲這幾個命令就是調用這幾個函數來實現的
10.1 link、unlink
10.1.1 硬鏈接
(1)ln命令創建硬鏈接: ln xxx.txt xxx1.txt
(2)創建硬鏈接,創建的是什麼 創建硬鏈接,就是再爲文件創建一個名字。
1)每創建一個硬鏈接,文件就多一個文件名,硬件鏈接數+1
從圖中看出,創建硬鏈接後所得到的多個文件名,指向的同一個inode節點,
只有inode節點代表了文件的真實存在,
inode節點只有一個,因此多個文件名指向的是同一個文件,不管使用的是哪一個文件名,都能操作這個文件。
2)硬鏈接數
記錄了有多少個文件名指向了inode節點,通過創建硬鏈接,每增加一個文件名,就多一個硬鏈接數。
3)刪除文件後,文件數據還在嗎?
還在,因爲刪除文件時,只是將文件的inode節點空間釋放了,如果這個文件有數據的話,
那麼這個文件的數據仍然還在,只要將文件的inode節點空間恢復,即可還原該文件。
4)有關目錄的硬鏈接數
(a)爲什麼新建的目錄一開始的文件鏈接數就是2
因爲新創建的目錄,一開始就有兩個名字指向了目錄的inode節點,分別是目錄的本名new和.
(b)爲什麼在該目錄下,每多創建一個目錄,當前目錄就會多一個硬鏈數
新創建目錄的..名字,也指向了當前目錄new。
(c)能不能使用ln命令,自己給目錄創建硬鏈接
答:不能,Linux不允許用戶自己給目錄創建硬鏈接,只能由Linux系統自己給目錄創建硬鏈接。
用戶只能給目錄以外的,其它類型的文件創建硬鏈接。
10.1.2 link函數
#include <unistd.h> int link(const char *oldpath, const char *newpath);
10.2 unlink函數
#include <unistd.h> int unlink(const char *pathname);
使用unlink創建臨時文件
所謂臨時文件就是,只在程序運行過程中有效,程序運行結束後就自動刪除,這就是臨時文件,
如何使用unlink創建臨時文件?
- open創建一個文件後(新文件的硬鏈接數都是1),然後立即調用unlink將文件硬鏈接數減爲0,將其刪除。
- 雖然文件的硬鏈接數變成了0,但是在進程沒有結束之前,這個文件仍然可以被使用,直到進程結束後,文件被刪
10.3、remove函數
10.3.1函數原型
#include <stdio.h> int remove(const char *pathname);
10.3.2 爲什麼這個函數既能用於刪除一般文件,也能用於刪除目錄
(1)remove是一個庫函數 它封裝了unlink和rmdir這兩個系統函數。
(3)rm命令
這個命令既能用於刪除目錄,也能用於刪除其它所有的文件,可以認爲就是調用remove實現。
10.4、rename函數
修改文件的路徑名,mv命令就是調用這個函數實現的。
函數原型
#include <stdio.h> int rename(const char *oldpath, const char *newpath);
1)修改路徑名情況1:當只改路徑,不改文件名字 : 這種情況其實就是移動。
如果文件移動起始位置和目標位置,在同一個分區裏面的話
- 移動文件時,不會移動文件的數據,只是把文件的基本信息(名字、inode編號),
- 從這個目錄記錄到另一個目錄下。
如果移動的起始位置和目標位置,不在同一個分區
- 既要移動數據,也要移動文件基本信息
在Linux下,分區是以目錄的形式存在的,而在windows分區是以c:等盤符形式存在。
2)修改路徑名情況2:不改路徑,只改文件名 這種情況就是一般意義上的改名。
3)修改路徑名情況3:既改路徑,也改文件名
11. symlink、readlink
這兩個函數與符號鏈接文件有關,(軟鏈接文件)
11.1 軟鏈接文件 (快捷圖標)
11.1.1 使用ln -s就可以創建符號鏈接文件
11.1.2 什麼是符號鏈接文件
符號鏈接文件就是一個快捷圖標,它指向了另一個文件
11.1.3 符號鏈接 與 硬鏈接的對比
(1)創建硬連接
同一個文件有多個不同的名字,它們指向是同一個inode節點。
(2)創建符號鏈接文件
符號鏈接文件與它所指向的文件,是兩個完全不同的獨立的文件,擁有自己獨立的inode節點。
符號鏈接文件的數據就是指向文件的文件名,文件大小就是名字的字符個數。
(3)不能給目錄創建硬鏈接,但是可以給目錄創建符號鏈接文
(4)可以給符號鏈接文件,創建硬鏈接嗎 可以
11.2 symlink
#include <unistd.h> int symlink(const char *oldpath, const char *newpath);
11.3 readlink
#include <unistd.h> ssize_t readlink(const char *path, char *buf, size_t bufsiz);
11.4 符號跟隨函數 與 符號不跟隨函數
(1) 符號跟隨函數
(2)符號不跟隨函數
12. getcwd、chdir、mkdir、rmdir
12.1 getcwd
這是一個庫函數,執行pwd命令就是調用這個函數實現的。
#include <unistd.h> char *getcwd(char *buf, size_t size);
pwd這個命令獲取的是,當前終端這個進程的工作路徑。
我自己的進程調用getcwd函數,獲取的是我自己進程的當前工作路徑,默認是你運行這個程序時所在的路徑。
12.2 chdir
#include <unistd.h> int chdir(const char *path);
12.3 mkdir函數
mkdir命令調用的就是這個函數。
#include <sys/stat.h> #include <sys/types.h> int mkdir(const char *pathname, mode_t mode);
12.4 rmdir函數
rmdir和rm命令刪除目錄時,調用的都是rmdir這個函數。
- rmdir命令:只能刪除空目錄,rmdir命令用的很少
- rm:不管目錄空不空,都能刪除,rm用的最多
函數原型
#include <unistd.h> int rmdir(const char *pathname);
如果目錄不爲空,必須遞歸調用rmdir函數,實現遞歸刪除。
什麼是遞歸刪除?
13. opendir、readdir
opendir:打開目錄,以便調用readdir讀取目錄項
readdir:讀取目錄裏面的目錄項
什麼是目錄項?
13.1 opendir
#include <sys/types.h> #include <dirent.h> DIR *opendir(const char *name);
13.2 readdir
#include <dirent.h> struct dirent *readdir(DIR *dirp);
14. chmode、fchmod
#include <sys/stat.h> int chmod(const char *pathname, mode_t mode); int fchmod(int fd, mode_t mode);