Linux編程學習筆記 | Linux IO學習[1] - 文件IO

系統(tǒng)調(diào)用與程序運行空間

在Linux操作系統(tǒng)中,為了提高系統(tǒng)的穩(wěn)定性庐橙,保證內(nèi)核的安全琳水,程序運行時的內(nèi)存空間被分為了用戶空間和內(nèi)核空間这吻。普通應用程序工作在用戶空間吊档,不能直接訪問內(nèi)核空間。它們需要使用Linux系統(tǒng)提供給用戶的一些"特殊接口" - 系統(tǒng)調(diào)用來安全地訪問內(nèi)核空間唾糯。

要對文件進行讀寫就需要使用Linux系統(tǒng)提供的一些系統(tǒng)調(diào)用怠硼。在這篇文章中我主要介紹 open() , write() , read() , lseek()close() 等函數(shù)鬼贱,在下文中我會詳細講解這些函數(shù)的使用。

文件描述符

在Linux系統(tǒng)中香璃,一切都可以被看作是文件这难,這包括:普通文件、目錄文件葡秒、鏈接文件和設備文件姻乓。要訪問文件,必須使用文件描述符眯牧。文件描述符是一個非負的整數(shù)蹋岩,它是系統(tǒng)中被打開文件的索引。當打開或者創(chuàng)建一個文件時学少,內(nèi)核會返回一個文件描述符剪个;當需要讀寫文件時,也需要將相應的文件描述符作為參數(shù)傳給讀寫函數(shù)版确。程序啟動時扣囊,默認有3個文件描述符:

文件描述符 說明
0 STDIN_FILENO 標準輸入
1 STDOUT_FILENO 標準輸出
2 STDERR_FILENO 標準錯誤輸出

如果此時創(chuàng)建或打開一個文件,這個文件的文件描述符就是3.

文件IO基本操作

打開/創(chuàng)建文件

open() 函數(shù)用于打開或者創(chuàng)建文件绒疗。其在打開或者創(chuàng)建文件時可以指定文件的屬性及用戶的權限等各種參數(shù)侵歇。要使用 open() 函數(shù),需要包含 #include <sys/stat.h>#include <fcntl.h> 這兩個頭文件忌堂。下面是函數(shù)的說明:

int open(const char *path, int oflag, [mode_t mode]);

args:
    const char *path: 文件路徑盒至,可以是絕對,也可以是相對路徑 
    int oflag       : 文件打開的方式
                        - O_RDONLY 只讀打開
                        - O_WRONLY 只寫打開
                        - O_RDWR   可讀可寫打開
                        以上3種必選一個士修,以下4種可以任意選擇
                        - O_APPEND 追加打開枷遂,所寫數(shù)據(jù)附加到文件末
                        - O_CREAT  若此文件不存在則創(chuàng)建它
                        - O_EXCL   若文件存在則報錯返回 
                        - O_TRUNC  如果文件已存在,并且以只寫或可讀可寫方式打開棋嘲,則將其長度截斷為0字節(jié)
    [mode_t mode]   : 文件權限酒唉,只有在創(chuàng)建文件時需要使用
    
return:
    文件描述符,非負整數(shù)是成功沸移,-1是失敗

open() 函數(shù)中痪伦,文件的打開方式不止上面的幾種,這里只列舉了常用的7種雹锣。注意网沾,新建文件的權限不是直接等于 mode 的值,而是等于 mode & ~uname 蕊爵。

寫文件

當文件打開后辉哥,我們就可以向該文件寫數(shù)據(jù)了。在Linux系統(tǒng)中,用 write() 向打開的文件寫入數(shù)據(jù)醋旦,要使用這個函數(shù)恒水,需要包含 #include <unistd.h> 。下面是函數(shù)的說明:

ssize_t write(int fildes, const void *buf, size_t nbyte);

args:
    int fildes     : 寫入文件的文件描述符
    const void *buf: 寫入數(shù)據(jù)在內(nèi)存空間存儲的地址
    size_t nbyte   : 期待寫入數(shù)據(jù)的最大字節(jié)數(shù)
    
return:
    文件實際寫入的字節(jié)數(shù)饲齐,非負整數(shù)是成功钉凌,-1是失敗(磁盤已滿或者超出該文件的長度等)

注意函數(shù)的返回類型是 ssize_tssize_tsize_t 類似捂人,只是 ssize_t 表示有符號數(shù)御雕。想了解更多 size_tssize_t 的區(qū)別請看這篇文章

讀文件

同寫文件類似先慷,要使用讀文件函數(shù) read() ,需要包含 #include <unistd.h> 饮笛。下面是函數(shù)的說明:

ssize_t read(int fildes, void *buf, size_t nbyte);

args:
    int fildes  : 讀取文件的文件描述符
    void *buf   : 讀取數(shù)據(jù)在內(nèi)存空間存儲的地址
    size_t nbyte: 期待讀取數(shù)據(jù)的最大字節(jié)數(shù)
    
return:
    文件實際讀取的字節(jié)數(shù),非負整數(shù)是成功论熙,-1是失敗

write() 一樣福青, read() 函數(shù)的返回類型也是 ssize_t

文件的偏移量

在每個打開的文件中都有一個文件的偏移量脓诡,文件的偏移量會根據(jù)文件的讀寫而改變位置无午。我們可以通過 lseek() 函數(shù)來調(diào)整文件的偏移量。默認情況下祝谚,新打開文件的文件偏移量在文件的開始宪迟。同 write()read() 函數(shù)類似,要使用這個函數(shù)交惯,需要包含 #include <unistd.h> 次泽。下面是函數(shù)的說明:

off_t lseek(int fildes, off_t offset, int whence);

args:
    int fildes  : 修改文件的文件描述符
    off_t offset: 文件偏移量移動的距離
    int whence  : 文件偏移量的基址
                    - SEEK_SET 文件開始處
                    - SEEK_CUR 文件當前位置
                    - SEEK_END 文件結束處
    
return:
    當前文件指針的位置,非負整數(shù)是成功席爽,-1是失敗

off_tssize_t 類似意荤,都是有符號數(shù)。

關閉文件

當文件不再被使用時只锻,可以調(diào)用 close() 函數(shù)來關閉被打開的文件玖像。
除了用 close() 顯示地關閉文件外,通過結束進程也能隱式地關閉被該進程打開的所有文件齐饮。要使用該函數(shù)捐寥,需要包含 #include <unistd.h> 。下面是函數(shù)的說明:

int close(int fildes);

args:
   int fildes: 要關閉文件的文件描述符
   
return:
    文件關閉狀態(tài)祖驱,0是成功握恳,-1是失敗

文件IO實例

文件基本操作

這是一個簡單的文件基本操作實例。在這個例子中捺僻,程序分兩次將內(nèi)存中的字符串寫入文件乡洼,然后又將文件內(nèi)容讀回內(nèi)存空間。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

/**
 * This is a simple example for using open(), write(), read(), lseek() and close().
 */
int main(int argc, char *argv[])
{
    int fd;
    ssize_t wr_size, rd_size;
    char buffer[128];
    char string_1[30], string_2[30] = "This is the second line!\n";
    char *path = "./file_io.log"; 
    
    fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 511);
    if (fd < 0) {
        printf("File create fail...\n");
        return -1; 
    } else {
        printf("File create success...\n");
    }
    
    /* write the first line to file_io.log */
    strcpy(string_1, "This is a demo for file_io!\n");
    wr_size = write(fd, string_1, strlen(string_1));
    if (wr_size < 0) {
        printf("File write 1 fail...\n");
        printf("wr_size = %d\n", wr_size);
        return -1; 
    } else {
        printf("File write 1 success...\n");
        printf("wr_size = %d\n", wr_size);
    }
    
    /* write the second line to file_io.log 
     * in this case, we only write 10 bytes data from string_2 to file.
     */
    wr_size = write(fd, string_2, 10);
    /* add "\0"(not '\0'!!) to the end of the second line */ 
    wr_size = write(fd, "\0", 1);
    if (wr_size < 0) {
        printf("File write 2 fail...\n");
        printf("wr_size = %d\n", wr_size);
        return -1; 
    } else {
        printf("File write 2 success...\n");
        printf("wr_size = %d\n", wr_size);
    }
    
    /* decrease current file offset by 20 bytes */
    lseek(fd, -20, SEEK_CUR);

    rd_size = read(fd, buffer, 100); 
    if (rd_size < 0) {
        printf("File read_1 fail...\n");
        printf("rd_size = %d\n", rd_size);
        return -1; 
    } else {
        printf("File read_1 success...\n");
        printf("rd_size = %d,\nbuffer = %s\n", rd_size, buffer);
    } 

    close(fd);
    
    return 0; 
}

編譯并運行該程序,程序和文件輸出結果如下:

程序輸出結果
文件輸出結果

對于上面的例子就珠,有幾點需要注意:

  1. 在40行處, wr_size = write(fd, string_2, 10); 我們寫入的字節(jié)數(shù)是小于 string_2 中的字節(jié)數(shù)的醒颖。如果想要寫入的字節(jié)數(shù)大于 string_2 中的字節(jié)數(shù)妻怎,那 string_2 外的字節(jié)也會寫入文件(這些額外的字節(jié)不是我們希望要的)。比如我們將40行改為 wr_size = write(fd, string_2, 100); 其輸出結果如下:
實際寫入的字節(jié)數(shù)大于需要寫入的字節(jié)數(shù)

2)如果注釋掉53行泞歉,則讀出的字節(jié)數(shù)為0逼侦,因為此時文件的偏移量處于文件的尾部。

忘記修改文件偏移量

簡易版CP指令

這是一個模仿Linux cp指令的小程序腰耙,這里并沒有考慮效率榛丢,也沒有考慮特殊情況,只是簡單地實現(xiàn)其功能挺庞。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

/* 
 * This a simple version of cp command. 
 */
int main(int argc, char *argv[])
{
    int fd1, fd2;
    ssize_t rd_size;
    char buffer[128];
    
    if (argc != 3) {
        printf("You should enter enter 2 parameters\n"); 
        return -1;
    }

    fd1 = open(argv[1], O_RDONLY);
    if (fd1 < 0) {
        printf("File %d does not exist...\n", fd1);
        return -1; 
    }
    fd2 = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 511); 
    if (fd2 < 0) {
        printf("File %d open fail...\n", fd2);
        return -1; 
    }

    while(read(fd1, buffer, 1))
        write(fd2, buffer, 1);

    close(fd1);
    close(fd2);
    
    return 0; 
}

編譯并運行該程序晰赞,程序輸出結果如下:

模仿CP指令

總結

這篇文章主要介紹了如何使用文件IO的系統(tǒng)調(diào)用函數(shù)對文件進行操作,文中出現(xiàn)的代碼都可在我的[github][7]上找到选侨。

如果覺得本文對你有幫助掖鱼,請多多點贊支持,謝謝援制!

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末戏挡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子晨仑,更是在濱河造成了極大的恐慌褐墅,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件洪己,死亡現(xiàn)場離奇詭異妥凳,居然都是意外死亡,警方通過查閱死者的電腦和手機码泛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門猾封,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人噪珊,你說我怎么就攤上這事晌缘。” “怎么了痢站?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵磷箕,是天一觀的道長。 經(jīng)常有香客問我阵难,道長岳枷,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮空繁,結果婚禮上殿衰,老公的妹妹穿的比我還像新娘。我一直安慰自己盛泡,他們只是感情好闷祥,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著傲诵,像睡著了一般凯砍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拴竹,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天悟衩,我揣著相機與錄音,去河邊找鬼栓拜。 笑死座泳,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的菱属。 我是一名探鬼主播钳榨,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼纽门!你這毒婦竟也來了薛耻?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤赏陵,失蹤者是張志新(化名)和其女友劉穎饼齿,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蝙搔,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡缕溉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了吃型。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片证鸥。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖勤晚,靈堂內(nèi)的尸體忽然破棺而出枉层,到底是詐尸還是另有隱情,我是刑警寧澤赐写,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布鸟蜡,位于F島的核電站,受9級特大地震影響挺邀,放射性物質(zhì)發(fā)生泄漏揉忘。R本人自食惡果不足惜跳座,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望泣矛。 院中可真熱鬧疲眷,春花似錦、人聲如沸您朽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽虚倒。三九已至,卻和暖如春产舞,著一層夾襖步出監(jiān)牢的瞬間魂奥,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工易猫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留耻煤,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓准颓,卻偏偏與公主長得像哈蝇,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子攘已,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理炮赦,服務發(fā)現(xiàn),斷路器样勃,智...
    卡卡羅2017閱讀 134,661評論 18 139
  • 一吠勘、溫故而知新 1. 內(nèi)存不夠怎么辦 內(nèi)存簡單分配策略的問題地址空間不隔離內(nèi)存使用效率低程序運行的地址不確定 關于...
    SeanCST閱讀 7,813評論 0 27
  • linux資料總章2.1 1.0寫的不好抱歉 但是2.0已經(jīng)改了很多 但是錯誤還是無法避免 以后資料會慢慢更新 大...
    數(shù)據(jù)革命閱讀 12,168評論 2 33
  • 開始本章學習之前了解一些概念: 1、帶緩存和不帶緩存IO 參考系統(tǒng)調(diào)用峡眶,用戶程序通過系統(tǒng)級別API調(diào)用系統(tǒng)函數(shù)將請...
    lifesmily閱讀 421評論 0 0
  • 在我職業(yè)生涯的十年里剧防,遇見過太多號稱財務自由的人,他們中的一部分財務狀態(tài)確實非常良好辫樱,大部分都是借錢讓自己過得瀟灑...
    南風大人閱讀 508評論 0 3