unix 檔案I O之詮釋

2021-06-04 03:14:51 字數 4492 閱讀 3133

unix系統中的大多數檔案i/o只需用到5個函式:open,read,write,lseek以及close.

其中open,create,fcntl,sync,fdatasync五個函式包含在標頭檔案中.

其它的close,lseek,read,write,pread,pwrite,dup,dup2包含在標頭檔案中.

而ioctl函式是i/or操作的雜物箱,不能用以上那些函式表示的i/o操作通常都能用ioctl表示,終端io是ioctl的最大使用方面,具體內容我將在"unix 檔案i/o之詮釋(二)等" 文章中闡述.

以下是五個常用函式的原型(open,read,write,lseek,close):

int open(const char *pathname, int oflag, ... );

對於open函式來講,僅當建立新檔案時才使用第三個引數.

第二個引數oflag的值有如:o_rdony (唯讀開啟),o_wronly (只寫開啟),o_rdwr(讀,寫開啟).

int close(int fields); //返回值:若成功則返回0,若出錯則返回-1

ssize_t read(int fieldes, void *buf, size_t nbytes);

//返回值:若成功則返回讀到的位元組數,若已到檔案結尾則返回0,若出錯則返回-1

ssize_t write(int fieldes, const void *buf, size_tnbytes);

//返回值:若成功則返回已寫的位元組數,若出錯則返回-1

off_t lseek(int filedes,off_t offset, int whence);//返回值:若成功則返回新的檔案偏移量,若出錯則返回-1

以下主要討論關於open,write等基本系統io的帶緩衝與不帶緩衝的差別

帶快取的檔案操作是標準c庫的實現,第一次呼叫帶快取的檔案操作函式時標準庫會自動分配記憶體並且讀出一段固定大小的內容儲存在快取中。所以以後每次的讀寫操作並不是針對硬碟上的檔案直接進行的,而是針對記憶體中的快取的。何時從硬碟中讀取檔案或者向硬碟中寫入檔案有標準庫的機制控制。不帶快取的檔案操作通常都是系統提供的系統呼叫,更加低階,直接從硬碟中讀取和寫入檔案,由於io瓶頸的原因,速度並不如意,而且原子操作需要程式設計師自己保證,但使用得當的話效率並不差。另外標準庫中的帶快取檔案io是呼叫系統提供的不帶快取io實現的。

「術語不帶緩衝指的是每個read和write都呼叫嗯核心中的乙個系統呼叫。所有的磁碟i/o都要經過核心的塊緩衝(也稱核心的緩衝區快取記憶體),唯一例外的是對原始磁碟裝置的i/o。既然read或write的資料都要被核心緩衝,那麼術語「不帶緩衝的i/o「指的是在使用者的程序中對這兩個函式不會自動緩衝,每次read或write就要進行一次系統呼叫。「--------摘自程式中用open和write開啟建立並把「helloworld「寫入檔案test.txt,相應用fopen和fwrite操作檔案test2.txt。程式執行到open和fopen之後,sleep15秒,這時用ls檢視生成了檔案沒,這時用open開啟的test.txt出現了,但是fopen的test2.txt沒有;當程式執行完write和fwrite之後,fopen的test2.txt仍然沒有出現(還是用ls檢視),再用cat看test.txt,可以看到「helloworld」;最後再關閉test.txt和test2.txt,這時test2.txt出現了,並且其內容也是「helloworld「。

該例子證明了open和write是不帶緩衝的,即程式一執行其io操作也立即執行,不會停留在系統提供的緩衝裡,不需等到close操作完才執行。與之相比的fopen和fwrite則是帶緩衝的,(一般)要等到fclose操作完後才會執行。

相關的原始碼示例如下:

#i nclude

#i nclude

#i nclude

#i nclude

#i nclude

#i nclude

using namespace std;

int main()

if(fwrite(s,sizeof(char),strlen(s),file)return -1; }

cout<<"afterwrite"cout<<"aftersleep."return 0;

}open函式的原型:

int open(const char *pathname, int oflag, ... );

close函式的原型:

int close (int fd);//成功返回0,失敗返回-1

示例:#i nclude

#i nclude

#i nclude

#i nclude

using namespace std;

int main()

read函式的原型:

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

//返回值:若成功則返回讀到的位元組數,若已到檔案結尾則返回0,若出錯則返回-1.

第三個引數在歷史上是乙個不帶符號整數,這允許乙個16位的實現一次讀或寫的資料可以多達65534個位元組,在1990posix.1標準中,引入了基本系統資料型別ssize_t以提供帶符號的返回值,不帶符號的size_t則用於第三個引數.

read函式是通過給定的檔案描述符,在檔案描述符所對應的檔案表項中獲得當前檔案偏移量,然後從檔案的當前偏移量處開始,讀取給定長度的資料放入buf中。

write函式的原型:

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

write函式是從檔案的當前偏移量處開始,將buf中的資料寫入檔案中。下面將程式2中的**做一修改,並假設info.txt檔案中已有資料abcde。

示例:#i nclude

#i nclude

#i nclude

#i nclude

#i nclude

#i nclude

using namespace std;

int main()

示例二:

#i nclude

#i nclude

#define buffsize 4096

using namespace std;

int main(void)

從以上程式注意以下幾點:

1.它從標準輸入讀,寫至標準輸出,這就假定在執行本程式之前,這些標準輸入,輸出已由shell安排好.所有常用的unix系統shell都提供一種方法,它在標準輸入上開啟乙個檔案用於讀,在標準輸出上建立(或重寫)乙個檔案.使得程式不必自行開啟輸入和輸出檔案.

2.很多應用程式假定標準輸入是檔案描述符0,標準輸出是檔案描述符1.分別用中定義的兩個常量stdin_fileno和stdout_fileno來表示.

3.考慮到程序終止時,unix系統核心會關閉該程序的所有開啟的檔案描述符,所以此示例並不會關閉輸入和輸出檔案.

4.對unix系統核心而言,文字檔案和二進位制**檔案的操作並無區別.

5.如何選取buffersize值.大多數檔案系統為改善其效能,都採用預讀技術,當檢測到正進行順序讀取時,系統就試圖讀入比應用程式所要求的更多資料.並假想應用程式很快就會讀這些資料.

作業系統試圖用快取技術將相關檔案放置在主存中,所以如若重複度量程式效能.那麼後續執行該程式所得到的計畫很可能好於第一次.其原因是,第一次執行使用檔案進入系統快取,後續各次一般從系統快取訪問檔案,而無需讀,寫磁碟.

lseek函式可以對乙個開啟檔案的當前位移量進行顯式地調整,其原型是:

以下程式用於測試能否對其標準輸入設定偏移量

#i nclude

#i nclude

using namespace std;

int main(void)

說明:lseek僅將當前的檔案偏移量記錄在核心中,它並不引起任何io操作.

示例二:

#i nclude

#i nclude

#i nclude

#i nclude

#i nclude

#i nclude

using namespace std;

int main()

{int i = open("info.txt",o_rdwr);

cout << "fd = "<< i <

int ii = open("new.txt",o_creat|o_excl,0700);

if(ii<0) cout <

char buf[500];

memset(buf,0x00,500);

cout << read(i,buf,500)<< "\t";

cout << buf<< endl;

memset(buf,0x00,500);

read(0,buf,500);

cout << write(1,buf,strlen(buf))<< endl;

errno = 0;

lseek(i,3,seek_set);  //lseek(i,-3,seek_set); //lseek(i,3,seek_end);

if(errno != 0) cout <

UNIX 檔案I O總結

輸入是從i o裝置拷貝資料到主存,輸出是從主存拷貝資料到i o裝置。乙個檔案就是乙個位元組序列。所有的i o裝置,如網路 磁碟 和終端,都被模型化為檔案,而所有的輸入和輸出都被當做想對應的檔案的讀寫來執行。1 iso c的i o操作是帶快取的,而posix標準的i o操作是指真正發生了系統呼叫,是不...

Unix高階程式設計 檔案I O

第3章檔案i o 3.1檔案描述符 fd stdin fileno 標準輸入 stdout fileno 標準輸出 stderr fileno 標準錯誤 乙個程序最多開啟63個檔案 3.2 open函式 include int open const char pathname,int oflag,m...

unix環境程式設計 檔案I O

unix 系統支援不同程序共享開啟檔案,下面解說核心用於所有i o的資料結構 核心使用了三種資料結構,它們之間的關係決定了檔案共享方面乙個程序對另外乙個程序可能產生的影響 每個程序在程序表中有乙個記錄項,每個記錄項中有一張開啟檔案的描述符的表,每個描述符佔一項,與每個描述符相關聯的是 a 檔案描述符...