Linux系統(tǒng)編程(一) ------ 文件操作函數(shù)

文件操作

打開文件

1.使用open()函數(shù)打開和創(chuàng)建文件

  • 手冊(cè)文件 man 2 open

函數(shù)頭文件及函數(shù)原型
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname替饿, int flags)整陌;
int open(const char *pathname癣籽, int flags豌习, mode_t mode);

函數(shù)參數(shù):

  pathname:待打開文件的絕對(duì)路徑和文件名。

  flags:打開的旗標(biāo)類型,或稱模式,
  O_RDONLY      只讀模式打開文件
  O_WRONLY      只寫模式打開文件
  O_RDWR        讀寫模式打開文件
  O_CREAT       若欲打開的文件不存在則自動(dòng)建立該文件
  O_TRUNC       若文件存在并且以可寫的方式打開時(shí)震糖, 此旗標(biāo)會(huì)令文件長(zhǎng)度清為0, 
                而原來存于該文件的資料也會(huì)消失趴腋。
  O_EXCL        如果O_CREAT 也被設(shè)置, 此指令會(huì)去檢查文件是否存在吊说。 
                文件若不存在則建立該文件,否則將導(dǎo)致打開文件錯(cuò)誤. 
                此外, 若O_CREAT 與O_EXCL 同時(shí)設(shè)置优炬,并且欲打開的文件為符號(hào)連接颁井, 
                則會(huì)打開文件失敗。

  參數(shù)mode僅在flags中含有O_CREAT時(shí)有效蠢护,設(shè)定新建文文件的打開權(quán)限雅宾,有下列數(shù)種組合,
  S_IRWXU             00700 權(quán)限,代表該文件所有者具有可讀葵硕、可寫及可執(zhí)行的權(quán)限眉抬。
  S_IRUSR 或S_IREAD,  00400 權(quán)限,代表該文件所有者具有可讀取的權(quán)限懈凹。
  S_IWUSR 或S_IWRITE, 00200 權(quán)限蜀变,代表該文件所有者具有可寫入的權(quán)限。
  S_IXUSR 或S_IEXEC,  00100 權(quán)限介评,代表該文件所有者具有可執(zhí)行的權(quán)限库北。
  S_IRWXG             00070 權(quán)限,代表該文件用戶組具有可讀们陆、可寫及可執(zhí)行的權(quán)限寒瓦。
  S_IRGRP             00040 權(quán)限,代表該文件用戶組具有可讀的權(quán)限坪仇。
  S_IWGRP             00020 權(quán)限杂腰,代表該文件用戶組具有可寫入的權(quán)限。
  S_IXGRP             00010 權(quán)限椅文,代表該文件用戶組具有可執(zhí)行的權(quán)限喂很。
  S_IRWXO             00007 權(quán)限际跪,代表其他用戶具有可讀衷笋、可寫及可執(zhí)行的權(quán)限庇麦。
  S_IROTH             00004 權(quán)限憋活,代表其他用戶具有可讀的權(quán)限穴张。
  S_IWOTH             00002 權(quán)限衍腥,代表其他用戶具有可寫入的權(quán)限蚪缀。
  S_IXOTH             00001 權(quán)限疹启,xit代表其他用戶具有可執(zhí)行的權(quán)限林说。

函數(shù)返回值: 打開文件成功煎殷,返回一個(gè)文件描述符 >2;打開失敗腿箩,返回-1豪直。

提示:使用 access()作用戶認(rèn)證方面的判斷要特別小心, 例如在access()后再作open()空文件可能會(huì)造成系統(tǒng)安全上的問題珠移。

2.使用create()函數(shù)創(chuàng)建并打開文件

函數(shù)原型

     int creat(const char *pathname, mode_t mode)弓乙;
     相當(dāng)于使用調(diào)用方式,
     open(const char *pathname, (O_CREAT|O_WRONLY|O_TRUNC))钧惧;

函數(shù)參數(shù):

  pathname   待打開文件的絕對(duì)路徑和文件名暇韧。

  mode       新創(chuàng)建文件的權(quán)限,見上面open()

函數(shù)返回值:若成功會(huì)返回新的文件描述符浓瞪,若有錯(cuò)誤發(fā)生則會(huì)返回-1懈玻。

提示:creat()無法建立特別的裝置文件,如果需要請(qǐng)使用mknod()乾颁。

讀寫文件

1.使用read()函數(shù)從文件中讀取數(shù)據(jù)

  • 手冊(cè)文件 man 2 read

函數(shù)頭文件及函數(shù)原型
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count)涂乌;

函數(shù)參數(shù):

 fd      文件指針,提供數(shù)據(jù)的文件的文件描述符英岭,讀取的數(shù)據(jù)的來源湾盒。

 buf     讀到的數(shù)據(jù)所存放的內(nèi)存空間的起始地址,同時(shí)文件的當(dāng)前讀寫位置向后移诅妹。

 count   想要讀取的數(shù)據(jù)的字節(jié)數(shù)历涝,也是提供的存儲(chǔ)空間字節(jié)數(shù)。

函數(shù)說明及返回值: read()會(huì)把參數(shù)fd 所指的文件傳送count 個(gè)字節(jié)到buf 指針?biāo)傅膬?nèi)存中(暨在[0,count]區(qū)間變化)漾唉。

1.若參數(shù)count 為0荧库,則read()不會(huì)有作用并返回0。
2.成功時(shí)赵刑,返回值為實(shí)際讀取到的字節(jié)數(shù)分衫。
3.如果返回0,表示已到達(dá)文件尾般此,暨碰到了EOF或是無可讀取的數(shù)據(jù)蚪战。
4.此外文件讀寫位置會(huì)隨讀取到的字節(jié)移動(dòng)牵现。
5.有錯(cuò)誤發(fā)生時(shí)則返回-1,而文件讀寫位置則無法預(yù)測(cè)邀桑。
提示:

read()函數(shù)負(fù)責(zé)從文件句柄中讀取指定數(shù)量的字節(jié)瞎疼,并將這些字節(jié)放在標(biāo)量型變量中。read()函數(shù)和標(biāo)準(zhǔn)I/O函數(shù)fread()相同的方式處理I/O緩沖的壁畸。為了提高效率贼急,read()函數(shù)并不是一次讀取一個(gè)字節(jié),而是讀取一塊數(shù)據(jù)并保存到臨時(shí)存儲(chǔ)區(qū)中捏萍。然后太抓,C的fread函數(shù)與Perl的read函數(shù)會(huì)從臨時(shí)緩沖區(qū)將數(shù)據(jù)一次一個(gè)字節(jié)地傳送給程序。print()函數(shù)(而不是write()函數(shù)負(fù)責(zé)輸出read()函數(shù)返回的實(shí)際字節(jié)令杈。print()函數(shù)類似于C中的fwrite()函數(shù)走敌。

附加:如果順利 read()會(huì)返回實(shí)際讀到的字節(jié)數(shù),最好能將返回值與參數(shù)count 作比較逗噩,若返回的字節(jié)數(shù)比要求讀取的字節(jié)數(shù)少掉丽,則
1. 讀取普通文件時(shí),讀到文件末尾還不夠 nbytes 字節(jié)异雁。例如:如果文件只有 30 字節(jié)机打,
而我們想讀取 100字節(jié),那么實(shí)際讀到的只有 30 字節(jié)片迅,read 函數(shù)返回 30 残邀。
此時(shí)再使用 read 函數(shù)作用于這個(gè)文件會(huì)導(dǎo)致 read 返回 0 。
2. 從終端設(shè)備(terminal device)讀取時(shí)柑蛇,一般情況下每次只能讀取一行芥挣。
3. 從網(wǎng)絡(luò)讀取時(shí),網(wǎng)絡(luò)緩存可能導(dǎo)致讀取的字節(jié)數(shù)小于 nbytes 字節(jié)耻台。
4. 讀取 pipe 或者 FIFO 時(shí)空免,pipe 或 FIFO 里的字節(jié)數(shù)可能小于 nbytes 。
5. 從面向記錄的設(shè)備讀取時(shí)盆耽,某些面向記錄的設(shè)備(如磁帶)每次最多只能返回一個(gè)記錄蹋砚。
6. 在讀取了部分?jǐn)?shù)據(jù)時(shí)被信號(hào)中斷。讀操作始于 cfo 摄杂。在成功返回之前坝咐,cfo 增加,
增量為實(shí)際讀取到的字節(jié)數(shù)析恢。

2.使用write()函數(shù)向指定文件中寫入數(shù)據(jù)
  • 手冊(cè)文件 man 2 write

函數(shù)頭文件及函數(shù)原型
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

函數(shù)參數(shù):

fd      待寫入數(shù)據(jù)的文件的描述符

buf     寫入數(shù)據(jù)的起始地址

count   待寫入的數(shù)據(jù)的字節(jié)數(shù)

函數(shù)說明及返回值: write()會(huì)把參數(shù)buf 所指的內(nèi)存寫入count 個(gè)字節(jié)到參數(shù)fd 所指的文件內(nèi)墨坚。當(dāng)然,文件讀寫位置也會(huì)隨之移動(dòng)映挂。
如果順利會(huì)返回實(shí)際寫入數(shù)據(jù)的字節(jié)數(shù)泽篮,表示寫了部分或者全部的數(shù)據(jù)盗尸。
當(dāng)有錯(cuò)誤發(fā)生時(shí),返回-1帽撑,我們要根據(jù)錯(cuò)誤的類型來處理泼各。如果錯(cuò)誤為EINTR表示在寫時(shí)出現(xiàn)了中斷錯(cuò)誤。如果為EPIPE表示網(wǎng)絡(luò)連接出現(xiàn)了問題亏拉。

提示:對(duì)于普通文件扣蜻,寫操作始于 cfo 。如果打開文件時(shí)使用了 O_APPEND专筷,則每次寫操作都將數(shù)據(jù)寫入文件末尾。成功寫入后蒸苇,cfo 增加磷蛹,增量為實(shí)際寫入的字節(jié)數(shù)。

定位文件

預(yù)概念: 所有打開的文件都有一個(gè)當(dāng)前文件偏移量(current file offset)溪烤,以下簡(jiǎn)稱為 cfo味咳。cfo 通常是一個(gè)非負(fù)整數(shù),用于表明文件開始處到文件當(dāng)前位置的字節(jié)數(shù)檬嘀。讀寫操作通常開始于 cfo槽驶,并且使 cfo 增大,增量為讀寫的字節(jié)數(shù)鸳兽。文件被打開時(shí)掂铐,cfo 會(huì)被初始化為 0,除非使用了 O_APPEND 揍异。

使用lseek()函數(shù)定位指定已打開文件的讀寫指針

  • 手冊(cè)文件 man lseek

函數(shù)頭文件及函數(shù)原型
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);

函數(shù)參數(shù):

fd 待重新定位讀寫指針位置的文件的描述符

offset 讀寫指針的偏移量(可正可負(fù)可為0)

whence 讀寫指針的偏移位置
    SEEK_SET   相對(duì)文件首部偏移全陨,文件偏移量將被設(shè)置為 offset。
    SEEK_CUR   相對(duì)文件當(dāng)前讀寫位置偏移衷掷,文件偏移量將被設(shè)置為 cfo 加上 offset辱姨,
               offset 可以為正也可以為負(fù)。
    SEEK_END   相對(duì)文件尾部偏移戚嗅,文件偏移量將被設(shè)置為文件長(zhǎng)度加上 offset雨涛,
               offset 可以為正也可以為負(fù)。

函數(shù)說明及返回值: 每一個(gè)已打開的文件都有一個(gè)讀寫位置懦胞,當(dāng)打開文件時(shí)通常其讀寫位置是指向文件開頭替久,若是以附加的方式打開文件(如O_APPEND),則讀寫位置會(huì)指向文件尾躏尉。當(dāng)read()或write()時(shí)侣肄,讀寫位置會(huì)隨之增加,lseek()便是用來控制該文件的讀寫位置醇份。參數(shù)fildes 為已打開的文件描述詞稼锅,參數(shù)offset 為根據(jù)參數(shù)whence來移動(dòng)讀寫位置的位移數(shù)吼具。當(dāng)調(diào)用成功時(shí)則返回目前的讀寫位置,也就是距離文件多少個(gè)字節(jié)數(shù)矩距。若有錯(cuò)誤則返回-1拗盒。

例:

 將讀寫位置移到文件開頭時(shí): lseek(int fildes, 0, SEEK_SET);
 將讀寫位置移到文件尾時(shí):   lseek(int fildes, 0, SEEK_END);
 想要取得目前文件位置時(shí):   lseek(int fildes, 0, SEEK_CUR);
提示:

1.Linux 系統(tǒng)不允許lseek()對(duì)tty 裝置作用,此項(xiàng)動(dòng)作會(huì)令lseek()返回ESPIPE锥债。
2.如果參數(shù) fd(文件描述符)指定的是 pipe(管道)陡蝇、FIFO 或者 socket,lseek 返回 -1 并且置 errno 為 ESPIPE哮肚。 對(duì)于普通文件(regular file)登夫,cfo 是一個(gè)非負(fù)整數(shù)。但對(duì)于特殊設(shè)備允趟,cfo 有可能是負(fù)數(shù)恼策。因此,我們不能簡(jiǎn)單地測(cè)試 lseek 的返回值是否小于 0 來判斷 lseek 成功與否潮剪,而應(yīng)該測(cè)試 lseek 的返回值是否等于 -1 來判斷 lseek 成功與否涣楷。
3.lseek 僅將 cfo 保存于內(nèi)核中,不會(huì)導(dǎo)致任何 I/O 操作抗碰。這個(gè) cfo 將被用于之后的讀寫操作狮斗。
4.如果 offset 比文件的當(dāng)前長(zhǎng)度更大,下一個(gè)寫操作就會(huì)把文件“撐大(extend)”弧蝇。這就是所謂的在文件里創(chuàng)造"空洞(hole)”碳褒。沒有被實(shí)際寫入文件的所有字節(jié)由重復(fù)的 0 表示】戳疲空洞是否占用硬盤空間是由文件系統(tǒng)(file system)決定的骤视。

關(guān)閉文件

使用close函數(shù)關(guān)閉指定文件

  • 手冊(cè)文件 man close

函數(shù)頭文件及函數(shù)原型

 #include <unistd.h>
 int close(int fd);

函數(shù)參數(shù):

fd    為open()或creat()打開的文件描述符。

函數(shù)說明及返回值: 當(dāng)使用完已打開的文件后若已不再需要?jiǎng)t可使用 close()關(guān)閉該文件, 而close()會(huì)讓數(shù)據(jù)寫回磁盤, 并釋放該文件所占用的資源. 參數(shù)fd 為先前由open()或creat()所返回的文件描述詞.**返回值:若文件順利關(guān)閉則返回0, 發(fā)生錯(cuò)誤時(shí)返回-1.

提示:雖然在進(jìn)程結(jié)束時(shí)鹃觉,系統(tǒng)會(huì)自動(dòng)關(guān)閉已打開的文件专酗,但仍建議自行關(guān)閉文件,并確實(shí)檢查返回值盗扇。

綜合案例

// ./my-cp <src_file> <dst_file>

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define BUFFER_SIZE 100

int main(int argc, char *argv[])
{
    if(argc != 3)
    {
        printf("usage : %s <src_file> <dst_file>\n",
            argv[0]);
        return 1;
    }
    
    int src_fd = 0;
    int dst_fd = 0;
    int n = 0;
    char buf[BUFFER_SIZE] = {'\0'};
    char *src_file = argv[1];
    char *dst_file = argv[2];
    
    // 1.open
    // 1.1 以只讀方式打開源文件
    if((src_fd = open(src_file, O_RDONLY)) == -1)
    {
        perror("open src error");
        return 1;
    }
    // 1.2 以只寫方式打開目的文件
    if((dst_fd = open(dst_file, 
            O_WRONLY | O_CREAT | O_TRUNC,
            S_IRUSR | S_IWUSR)) == -1)
    {
        perror("open dst error");
        return 1;
    }
    
    // 2. 循環(huán)從源文件中讀取數(shù)據(jù)寫入到目的文件中
    // 直到讀到源文件的尾部為止
    // 2.1 read data from src_file
    // 2.2 write data to dst_file
    while((n = read(src_fd, buf, BUFFER_SIZE)) > 0)
    {
        write(dst_fd, buf, n);
    }
    
    // 3.close
    close(src_fd);
    close(dst_fd);

    return 0;
}

// 練習(xí):
// 實(shí)現(xiàn)一個(gè)相對(duì)完整版的cp程序祷肯,要求能夠判斷出目標(biāo)文件是否存在。
//  如果存在疗隶,給出提示是否覆蓋佑笋。
// 思路:
// 1.打開源文件
// 2.判斷目的文件是否存在
// 3.如果目的文件存在,提示是否覆蓋
// 4.如果選擇覆蓋斑鼻,則以只寫的方式打開文件蒋纬,并截短文件內(nèi)容(O_TRUNC)
// 5.如果選擇不覆蓋,則提醒輸入新的保存文件名,并已只寫方式打開
// 6.循環(huán)讀取源文件內(nèi)容蜀备,寫入到目的文件中
// 7.關(guān)閉已打開的文件

// 思考題1:能否關(guān)閉標(biāo)準(zhǔn)輸入文件关摇、標(biāo)準(zhǔn)輸出文件碾阁、標(biāo)準(zhǔn)出錯(cuò)文件?

參考資料

劉老師上課資料及網(wǎng)上前輩資料
計(jì)算機(jī)操作系統(tǒng)教程:介紹現(xiàn)代操作系統(tǒng)原理及應(yīng)用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末脂凶,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蚕钦,更是在濱河造成了極大的恐慌亭病,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件罪帖,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡食听,警方通過查閱死者的電腦和手機(jī)污茵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門樱报,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人泞当,你說我怎么就攤上這事迹蛤〗笫浚” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵陋桂,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我嗜历,道長(zhǎng),這世上最難降的妖魔是什么梨州? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮暴匠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘帮掉。我一直安慰自己弦悉,他們只是感情好旭寿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著盅称,像睡著了一般。 火紅的嫁衣襯著肌膚如雪缩膝。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天将饺,我揣著相機(jī)與錄音,去河邊找鬼予弧。 笑死,一個(gè)胖子當(dāng)著我的面吹牛掖蛤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蚓庭,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼器赞!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起港柜,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤咳榜,失蹤者是張志新(化名)和其女友劉穎夏醉,沒想到半個(gè)月后贿衍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贸辈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年释树,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了肠槽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡秸仙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出寂纪,到底是詐尸還是另有隱情,我是刑警寧澤捞蛋,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布柬姚,位于F島的核電站拟杉,受9級(jí)特大地震影響量承,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜撕捍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望忧风。 院中可真熱鬧,春花似錦阀蒂、人聲如沸弟蚀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至捶闸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間删壮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工央碟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓苞也,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親如迟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

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