在Linux下,一切皆文件。這是咱們嵌入式Linux開發與應用這門課的老師常常掛在嘴邊的一句話。足以體現出在Linux操做系統中,對於一切資源的管理都是對文件的操做。shell
Linux系統中每個分區都是一個文件系統,都有本身的目錄層次。Linux會將這些在不一樣分區的,單獨的文件系統按必定的方式造成一個系統的總目錄層次結構。數組
Linux下能夠經過shell命令來操做文件,可是功能有必定限制;咱們也能夠經過系統調用或者C語言的庫函數對文件進行操做socket
Linux下的文件主要包括兩方面的數據:文件自己所包含的數據,以及文件屬性,也稱爲元數據。函數
目錄在Linux下也是文件,稱爲目錄文件。目錄文件的內容是該目錄的目錄項,目錄項是該目錄下的文件和目錄相關的信息。每當建立一個新目錄的時候,OS會自動建立兩個目錄項——「.」和「..」測試
Linux採用的是標準的目錄結構——樹形結構(B樹家族)spa
Linux既然採用了樹形結構的目錄形式,整個OS只有一棵文件樹,這樣方便OS對文件進行統一管理。Linux操做系統中的這顆文件樹的樹根叫作根文件系統,用「/」表示,能夠經過使用cd /命令直接到達根目錄。各個磁盤是經過掛載以文件夾的形式訪問操作系統
根文件系統:3d
/bin:該目錄下存放供用戶使用的完成基本維護任務的命令.指針
/boot:該目錄下存放着和OS啓動時使用的一些核心文件。code
/dev:該目錄中包含全部的系統設備文件。從該目錄能夠訪問各類系統設備,它還包含了建立設備文件的MAKEDEV.
/home:該目錄存儲普通用戶的我的文件,每一個用戶的主目錄均在/home下以用戶名命名的文件夾。
/etc:該目錄包含系統和應用軟件的配置文件。
/lib:該目錄存放着系統最基本的共享連接庫(至關於Windows下的DLL)和內核模塊。
/lib64:若是是64位系統,它會有這個,存放64程序的共享連接庫,同時也會有一個lib32.
/media:可移動設備的掛載點,OS一般把U盤等設備自動掛載到該目錄下。
/opt:第三方的軟件默認安裝到這個位置。並非每一個Linux發行版都會建立這個目錄。
/mnt:臨時用於掛載文件系統的。通常狀況下這個目錄下是空的,在咱們掛載分區的時候會在該目錄下建立目錄。
/proc:存在於內存中的虛擬文件系統,裏面保存了內核和進程的狀態信息。
/root:這是root(超級管理員)用戶的主目錄,於/home下的普通用戶目錄類型。
/sbin:供root用戶使用的可執行文件,可能是系統管理命令。
/usr:靜態的用戶級應用程序。
/tmp:該目錄用於保存臨時文件。
Linux文件分類:
普通文件:用戶和OS的數據,程序等信息文件
目錄文件:Linux文件系統將文件索引節點號和文件名同時保存在目錄中,因此目錄就是一張表。OS能夠修改目錄文件,用戶只能讀目錄文件
設備文件:Linux下一切皆文件,設備也是文件。每一種I/O設備對應一個設備文件,存放於/dev下。
管道文件:這是Linux用於進程之間通訊的文件,一個進程在管道這一段寫入數據,另外一個進程在管道的另外一端讀取數據。管道文件通常是FIFO文件。
連接文件:又被稱做符號連接文件,它提供了一種共享文件的方式。它包含了指向文件的指針。
經過ls -l能夠查看文件類型和屬性
結果分多行顯示,距離說明一下每行顯示的意義。例如第一行exec這個文件的信息行。首先,咱們看到這行以「-」開頭,表示exec是一個普通文件。同時注意到第三行以d開頭,這說明new是一個目錄文件。
接着看第一個符號後面的信息,注意到後面仍舊有9個字符。這9個字符分紅3組,即每3個一組,」w"表示可寫,「r」表示可讀,「x」表示可執行。第一組3個符號表示的是文件擁有者對該文件的權限;第二組3個符號表示該文件所在組的其餘擁有者對該文件的權限;第3組表示系統其餘用戶對該文件的權限。
繼續能夠看到有個數字,對於普通文件,這個數字表示連接數,對於目錄文件來講這個數字表示第一級子目錄數。接下來的兩組信息分別是用戶名和組名,而後是文件大小(單位是字節),接着是文件最後的修改日期,最後就是文件名。
Linux文件描述符
在Linux下當一個進程打開文件的時候,OS會返回相應的文件描述符,程序爲了處理該文件必須使用這個文件描述符。文件描述符是一個正整數。通常而已,當一個進程啓動的時候,他會打開3個文件:標準輸入,標準輸出,標準錯誤。這3個文件對應的文件描述符分別是0,1,2.一般使用宏:STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO.文件描述符是一個索引,指向內核中打開文件的記錄表。
Linux操做系統給咱們提供了6個系統調用create,open,write,close,read,lseek。系統調用是不帶緩衝區的。他們是POSIX標準提供的。這些函數須要的頭文件#include<fcntl.h>,#include<sys/types.h>,#include<sys/stat.h>。
create函數用於建立一個文件,它的功能能夠被open函數取代,open函數由3個參數的時候,就能夠當作create函數使用,這時若是文件不存在,open就會建立這樣一個文件。例如:open(path,O_WRONLY|O_CREAT|O_TURNC,mode);而且open彌補了create的一個不足之處是:create建立的文件是以只寫方式打開所建立的文件,因此當須要讀取的時候,須要先close,而後在open一次。如今則能夠這樣:open(path,O_RDWR|O_CREAT|O_TRUNC,mode);
mode值包含了對文件的訪問權限位。正如上面描述的同樣,每一個文件有9個訪問權限位,而且能夠分爲3組。
mode |
含義 |
S_IRUSR | 用戶讀 |
S_IWUSR | 用戶寫 |
S_IXUSR | 用戶執行 |
S_IRGRP | 組讀 |
S_IWGRP | 組寫 |
S_IXGRP | 組執行 |
S_IROTH | 其餘讀 |
S_IWOTH | 其餘寫 |
S_IXOTH | 其餘執行 |
若是打開的文件是在某個目錄文件下,那麼該目錄應該是可執行的,由於對於目錄文件而言,可執行表明着搜索位,咱們能夠找該目錄下的文件。目錄的讀只表明咱們能夠讀取該目錄的文件列表,不能進行其餘操做。若是當前打開了一個文件,若是是root用戶的進程,那麼它確定能訪問該文件。若是進程是文件全部者執行的,那麼對文件的權限取決於第一組的權限;若是進程是文件全部者所在組或者附屬組之一,那麼對文件的權限取決於第二組權限。若進程是其餘用戶執行的,那麼對文件的操做取決於第三組權限。
在使用open函數打開一個文件的時候,最經常使用的三個參數是:O_WRONLY(只寫),O_RDONLY(只讀),O_WRRD(可讀可寫)
另外兩種是:O_EXEC(執行),O_SEARCH(搜索,應用於目錄)。另外open打開的文件,返回的文件描述符必定是最小的未使用描述符。path所指定的路徑能夠是絕對路徑,也能夠是相對路徑。
read函數用於從已打開的文件中讀取數據
若是read成功,返回讀取到的字節數。若已到達文件尾端,返回0。讀取出錯返回-1.
write函數用於講數據寫入已打開的文件中
若是寫入成功,返回以寫字節數,不然,返回-1.
close函數用於關閉文件
關閉一個文件並釋放該進程加在該文件上的全部鎖。當一個進程終止的時候,會自動關閉它打開的全部文件。全部有時候並不顯式的使用close關閉文件。返回0表示成功,返回-1表示錯誤。
lseek函數用於移動文件的讀寫位置。
每一個打開文件都有一個與其相關聯的「當前文件偏移量」。用於計算從文件開始處的字節數。一般,讀寫都是從當前文件偏移量處開始的,並使用偏移量增長所讀寫的字節數。系統默認該偏移量爲0。可使用lseek函數來指定一個打開文件的偏移量。
一個簡單的例子以下:
#include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<stdio.h> #include<string.h> #include<stdlib.h> #include<unistd.h> int main() { int fd,size; int l; char str[] = {"This is My Schoolnumber:1507050314"}; char tmp[51] = {0}; fd = creat("hello.txt",(S_IRUSR|S_IWUSR)); //在當前目錄建立一個hello.txt文件,他是可讀可寫的。 write(fd,str,strlen(str)); //寫入This is My Schoolnumber:這句話 close(fd); //關閉文件 open("hello.txt",O_RDONLY); //以只讀方式打開文件 read(fd,tmp,strlen(str)); //讀文件 close(fd); //關閉文件 printf("%s\n",tmp); return 0; }
打印結果以下:
須要注意的是,tmp數組須要所有初始化爲0,'\0'的ASCII就是0.這樣將打開的文件中讀取的文本信息打印的時候才能正常打印,不會亂碼。不然不知道在哪兒終止,將會產生亂碼。
注意:在使用Linux的系統調用操做文件的時候,是無緩衝的,這點很重要。當你在作少許,大批次寫入的時候效率會很低。所以注意使用緩衝(用數組的之類的暫時保存一下),能提升I/O效率。
另一個測試程序以下:
#include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<stdio.h> #include<string.h> #include<stdlib.h> #include<unistd.h> int main() { int fd,size; int l; char str1[] = {"This is My Schoolnumber:1507050314\n"}; char str2[] = {"This is My Schoolnumber:1507050316\n"}; char tmp[51] = {0}; fd = creat("hello.txt",(S_IRUSR|S_IWUSR)); //在當前目錄建立一個hello.txt文件,他是可讀可寫的。 write(fd,str1,strlen(str1)); //寫入This is My Schoolnumber:這句話 close(fd); //關閉文件 open("hello.txt",O_RDWR|O_APPEND); //以可讀可寫,寫追加方式打開文件 lseek(fd,5,SEEK_CUR); //更改文件偏移量,從5這個位置開始計算偏移量 read(fd,tmp,strlen(str1)); //讀文件 write(fd,str2,strlen(str2)); //寫文件 close(fd); //關閉文件 printf("%s",tmp); return 0; }
運行結果以下:
打印的是「is My Schoolnumber」,沒有了This。說明更改這個當前文件偏移量成功了。使用cat命令打印Hello.txt文件的內容,能夠看到寫入也是成功的。
lseek不能夠用於管道,FIFO,socket文件。另外lseek的文件偏移量的大小能夠大於當前文件的長度,在這種情形下,對該文件的下一次寫將加長該文件,並在文件中構成一個空洞。文件空洞並不要求在磁盤上佔據空間。