Linux system programming

來源:互聯網
上載者:User

第一章:介紹與基本概念
 
1.Linux遵循一切皆檔案的哲學,檔案通過獨一無二的檔案描述符來引用,(file  descriptior,簡稱fd ),檔案描述符是一個整數(c的int  類型)。fd由使用者空間程式所共用,而使用者空間程式可以直接使用fd來訪問檔案。
 
2.常規檔案內含資料位元組,而且被組織成一個稱為位元組流(byte stream)的線性數組(linear  array)。這些位元組流可以具有任何價值,而且可以通過任何方式被組織在一起。從系統層面看,除了位元組流,linux不會再對檔案套上任何結構.
一個檔案首次被開啟時,檔案位置是零,可以手動設定檔案的位置,若設定為檔案末尾,那麼直接寫入檔案位置末尾之後的位置,則會使中間的位元組被補上零,不能將位元組寫到檔案開頭之前的位置。
將一個位元組寫入檔案的中間位置,會覆蓋之前位於該位移量的位元組。因此,將自己寫入檔案的中間位置是不可能擴大檔案的。


第二章:檔案I/O
************************************************
open()系統調用用來將路徑名稱name所指定的檔案對應至一個檔案描述符,並與映射成功後返回該檔案描述符,檔案位置會被設定為零。
int open(const char *name,int flags);
int open(const char *name,int flags,mode_t mode);
除非是在建立新檔案,否則mode參數會被忽略掉。


int fd;

fd = open("/home/kidd/madagascar",O_RDONLY);
if(fd == -1)
/* error*/
****************************************************

creat()  即為O_WRONLY | O_CREAT| O_TRUNC參數的open調用

int creat (const char *name,mode_t mode);

int fd;
fd = creat(file,644);
if(fd == -1)
/*   error*/
*****************************************************
#include<unistd.h>

ssize_t read (int fd,void *buf,size_t len);

每次調用會從fd參數所引用的當前檔案位置讀取len個位元組到buf,執行成功後會返回寫入buf的位元組數目,失敗則返回-1並設定errno。檔案位置會前進從fd所讀取的位元組數目,如果fd不具備尋找位置的能力(字元裝置檔案),則每次只會從當前位置讀取資料。
unsigned long word;
ssize_t nr;

nr = read(fd,&word,sizeof(unsigned long));
if(nr == -1)
/*error*/

read()返回小於len的非零正數:可供讀取的位元組數目少於len,系統調用可能收到訊號而中斷,管道可能壞了(如果fd是管道)等。

read()返回零以指示到達了檔案的末端(end of file  簡稱EOF),阻擋模式下,此調用會受到阻擋(進入休眠狀態),直到出現可供讀取的位元組;非阻擋模式下,調用返回-1,稍後應該在進行此調用。

讀取所有位元組:
ssize_t ret;

while(len != 0 && (ret = read(fd,buf,len)) != 0){
if(ret == -1){
if(errno == EINTR)
continue;
perror("read");
break;
}
len -= ret;
buf +=ret;
}

非阻擋式讀取操作:必須檢查EAGAIN,否則就會“嚴重錯誤”和“只是缺乏資料”相混淆
char buf[BUFSIZ]
ssize_t nr;
start:
nr = read(fd,buf,BUFSIZ);
if(nr == -1){

if(errno == EINTR)
goto start;
if(errno == EAGAIN)
/* later  */
else
/*  error*/
}
****************************************************************************

write()系統調用:
#include<unistd.h>

ssize_t write(int fd,const void *buf,size_t count);

進行write()調用,就會從buf開始將count個位元組寫入fd所指檔案的當前檔案位置。如果fd所指對象不支援尋找功能(字元裝置),則總是會從(head)寫起。
成功返回寫入位元組,發生錯誤則返回-1,返回0僅意味著寫入了0位元組。
基本用法:
const char *buf = "my ship is solid";
ssize_t nr;
nr = write (fd,buf,strlen(buf));
if(nr == -1)
/**error/

檢查部分寫入的可能性

………………
else if(nr != count)
/*maybe error,but not errno*/

Linux寫入為延後寫入
*****************************************************************************

fsync()系統調用:
#include<unistd.h>

int fsync(int fd);

調用fsync()可以確保檔案描述符fd所映射的檔案中所有髒資料會被寫回磁碟。fd必須被開啟以備寫入。此調用會寫回資料和中繼資料,並且等到硬碟回報資料與中繼資料已經寫回磁碟才返回。

fdatasync()系統調用:
#include<unistd.h>

int fdatasync(int fd);

此調用和fsync的行為是一樣的,但是它只會重新整理資料(flush data)。此調用無法保證資料與磁碟是同步的,因此速度可能會更快

兩個函數用法一樣:
int ret;

ret = fsync(fd);
if(ret == -1)
/*error*/

這兩個函數無法保證包含檔案的目錄項如果有任何變動都能夠與磁碟同步化。為了確保目錄項的任何變動也能寫回磁碟,必須針對目錄本身調用fsync()。

sync()系統調用:

可以讓所有緩衝區與磁碟同步化

#include<unistd.h>

void sync(void);

此函數不需要參數,也沒有傳回值,但是能夠成功返回。

標準沒有要求sync()必須等到所有緩衝區全都被清空到磁碟才返回,只要求該調用將所有緩衝區交付給磁碟,然而linux會等到所有緩衝區都被交付為止,因此調用一次sync就夠了,
應用程式應該使用fsync和fdatasync將必要的資料提交給磁碟,在忙碌的系統中,sync()調用可能需要花費幾分鐘的時間。

ps:

O_SYNC標誌
將O_SYNC標誌傳遞給open()表示檔案的所有io都需要同步化:

int fd;

fd = open(file,O_WRONLY|O_SYNC);
if(fd == -1){
perror("open");
return -1;
}
讀取請求通常需要同步化,否則無法知道緩衝區中提供的資料是否正確。然而,如前所述write()調用通常不需要同步,此調用返回與資料是否提交給磁碟並無關係。
然而使用O_SYNC標誌可以建立此關係,確保write()執行io同步化。具體步驟:
每次在write()調用之後和返回之前隱式調用fsync().這樣會使寫入操作的使用者時間和核心程式的時間變差。除非不得以,否則最好不要用同步化io。
通常,應用程式使用fsync和fdatasync來保證寫入操作已經將資料寫回磁碟,相比較O_SYNC這麼做的成本比較低,因為他們被調用的機會比較少。
****************************************************************************
close()系統調用
#include<unistd.h>
int close(int fd);

取消已開啟檔案描述符fd的映射關係,讓進程與相關聯檔案分離。執行成功會返回零,失敗返回-1並且設定errno。最常見的錯誤就是沒有檢查close()的傳回值,導致錯過嚴重錯誤。
基本用法:
if(close(fd) == -1)
perror("close");
*****************************************************************************
lseek()系統調用
#include<sys/types.h>
#include<unistd.h>

off_t lseek(int fd ,off_t pos,int origin);

lseek()的行為取決於origin參數:

SEEK_CUR   檔案位置被設定為它的當前值加上pos
SEEK_END   檔案位置被設定為檔案的當前長度加上pos
SEEK_SET   檔案的位置被設定為pos,當pos為零時,位移值會被設定為檔案的開頭。

例如將檔案的位置設定為1825

off_t ret;
ret = lseek(fd,(off_t)1825,SEEK_SET);
if(ret == (off_t)-1)
            /*error*/

將fd的位置設定為檔案的末端:
off_t ret;
ret = lseek(fd,0,SEEK_END);
if(ret == (off_t)-1)
/*error*/

尋找當前位置:
int pos;
pos = lseek(fd,0,SEEK_CUR);
if(pos == (off_t)-1)
/*error*/
else
 /*pos 是檔案當前位置*/

*****************************************************************************************8

針對特定位置的讀取和寫入

讀取:
#define _XOPEN_SOURCE 500
#include <unistd.h>
ssize_t pread(int fd,void *buf,size_t count,off_t pos);
從檔案描述符的檔案位置pos讀取count個位元組到buf。

寫入:
#define _XOPEN_SOURCE  500
#include <unistd.h>
ssize_t pwrite(int fd,const void *buf,size_t count,off_t pos);
會將count個位元組從buf寫入檔案描述符fd的檔案位置pos

和read()或write()的不同:
1.完成工作後不會改變檔案指標。
2.可以避免使用lseek()時造成的競爭條件,如果有多個線程共用檔案描述符,當第一個線程調用lseek()之後,在它進行讀取或者寫入操作之前,同一個程式的另一個線程可能會改變檔案的位置,使用pread()和pwrite()可避免此類競爭條件。

************************************************************************************

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.