Linux文件及文件I/O

在Linux下,一切皆文件。這是咱們嵌入式Linux開發與應用這門課的老師常常掛在嘴邊的一句話。足以體現出在Linux操做系統中,對於一切資源的管理都是對文件的操做。shell

Linux系統中每個分區都是一個文件系統,都有本身的目錄層次。Linux會將這些在不一樣分區的,單獨的文件系統按必定的方式造成一個系統的總目錄層次結構。數組

Linux下能夠經過shell命令來操做文件,可是功能有必定限制;咱們也能夠經過系統調用或者C語言的庫函數對文件進行操做socket

  1. Linux下的文件主要包括兩方面的數據:文件自己所包含的數據,以及文件屬性,也稱爲元數據。函數

  2. 目錄在Linux下也是文件,稱爲目錄文件。目錄文件的內容是該目錄的目錄項,目錄項是該目錄下的文件和目錄相關的信息。每當建立一個新目錄的時候,OS會自動建立兩個目錄項——「.」和「..」測試

  3. 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文件分類:

  1. 普通文件:用戶和OS的數據,程序等信息文件

  2. 目錄文件:Linux文件系統將文件索引節點號和文件名同時保存在目錄中,因此目錄就是一張表。OS能夠修改目錄文件,用戶只能讀目錄文件

  3. 設備文件:Linux下一切皆文件,設備也是文件。每一種I/O設備對應一個設備文件,存放於/dev下。

  4. 管道文件:這是Linux用於進程之間通訊的文件,一個進程在管道這一段寫入數據,另外一個進程在管道的另外一端讀取數據。管道文件通常是FIFO文件。

  5. 連接文件:又被稱做符號連接文件,它提供了一種共享文件的方式。它包含了指向文件的指針。

經過ls -l能夠查看文件類型和屬性

結果分多行顯示,距離說明一下每行顯示的意義。例如第一行exec這個文件的信息行。首先,咱們看到這行以「-」開頭,表示exec是一個普通文件。同時注意到第三行以d開頭,這說明new是一個目錄文件。

  • -:表示普通文件
  • d:表示目錄文件
  • l:表示連接文件
  • c:表示字符設備
  • b:表示塊文件
  • p:表示管道文件
  • f:表示堆棧文件

接着看第一個符號後面的信息,注意到後面仍舊有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的文件偏移量的大小能夠大於當前文件的長度,在這種情形下,對該文件的下一次寫將加長該文件,並在文件中構成一個空洞。文件空洞並不要求在磁盤上佔據空間。

相關文章
相關標籤/搜索