Unix高階程式設計學習筆記(2)

2021-07-05 05:33:07 字數 4481 閱讀 3754

linux系統可以看成是乙個由檔案組成的系統,在linux系統中,基本上所有的裝置,硬體,資源都被看成乙個檔案,比如,在/dev下面我們可以看到我們的硬碟sda1,終端裝置ttyn,在/proc目錄下面我們可以看到當前的記憶體資訊,cat /proc/meminfo,可以檢視cpu的資訊: cat /proc/cpuinfo , 這些檔案都是被linux系統抽象成了乙個個的檔案,通過對檔案的操作來,對具體的硬體操作。

對乙個檔案的操作可以分為,開啟, 讀取,寫入,關閉等,因此我們對硬體裝置檔案的操作也抽象成了,對其檔案的讀取,寫入,比如:我們要列印乙個字串到螢幕上,在linux裡面螢幕這個硬體被抽象成了乙個檔案,我們可以通過往那個檔案裡面寫入字串,來實現列印。再比如現在有乙個串列埠,他要和其它的乙個pc通過串列埠通訊,這個串列埠在系統裡也被抽象成了乙個檔案,我們可以通過從檔案讀來取出串列埠上發過來的資料,通過寫入,來向另外乙個pc傳送資料。看下面的程式:

#include 

#include

int main(void)

它就是向stdout_fileno這個檔案裡面寫入helloworld 這11個字元,這個stdout_fileno是什麼東西呢?這個定義在了/usr/include/unistd.h檔案裡,定義如下:

#define stdin_fileno    0       /* standard input.  */

#define stdout_fileno 1 /* standard output. */

#define stderr_fileno 2 /* standard error output. */

通過後面的注釋可以看出,這個巨集定義表示的是標準輸出,也就是螢幕,那它為什麼是1呢。我們引出了下面的術語,檔案描述符(file descriotor)

對於核心而言,所有開啟檔案都由檔案描述符引用。檔案描述符是乙個非負整數。當開啟乙個現存盤案或建立乙個新檔案時,核心向程序返回乙個檔案描述符。當讀、寫乙個檔案時,用open或creat返回的檔案描述符標識該檔案,將其作為引數傳送給read或write。

有三個特殊的檔案描述符,每個程序在建立時,都預設開啟三個檔案描述符。

上面的stdout_fileno就是標準輸出檔案描述符,它和我們標準c庫里的檔案指標很相似,只是相似,完全不一樣。

其實如果你分析了核心的原始碼後會發現,檔案描述符,其實是當前程式開啟檔案結構陣列的下標,當乙個程式啟動時,系統預設的讓他開啟了三個檔案,就是標準輸入,標準輸出,標準錯誤輸出,它們的在開啟檔案結構資料的下標就是0,1,2,因此,如果我的程式再開啟乙個新的檔案,那麼應該這個下標(檔案描述符)就應該是3.

檔案描述符的範圍是0 ~ open_max 。open_max 具體值是多少,可以運用grep命令去搜尋。

open()函式

看其字面意思就是開啟一檔案的意思。下面看它的具體

#include 

#include

#include

int open(const

char *pathname, int oflag);

int open(const

char *pathname, int oflag, mode_t mode);

返回值:若成功為檔案描述符,若出錯為- 1 (與fopen區別開null,因為他返回的是file指標)

pathname:是要開啟或建立的檔案的名字。

oflag引數(定義在fcntl.h標頭檔案):

mode引數:

open不僅可以開啟乙個檔案,也可以去建立乙個檔案,這一點要注意下,其實在系統呼叫函式裡面,還有乙個真正的建立檔案呼叫函式,creat函式。

#include 

#include

#include

int creat(const

char * pathname, mode_t mode) ;

功能:建立乙個新的檔案。

返回值:若成功為只寫開啟的檔案描述符,若出錯為- 1。

注意,此函式等效於:

open (pathname, o_wronly | o_creat | o_trunc, mode) ;

creat的乙個不足之處是它以只寫方式開啟所建立的檔案不能讀。

read函式

#include 

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

功能:從開啟檔案中讀資料

返回:讀到的位元組數,讀不到位元組返回0,若count 為0返回0,若出錯為- 1。

有多種情況可使實際讀到的位元組數少於要求讀位元組數:

wirte函式

#include 

ssize_t write(int fd, const

void *buf, size_t count);

功能:向開啟檔案寫資料。

返回:若成功為已寫的位元組數,若出錯為- 1。

其返回值通常與引數count的值不同,否則表示出錯。write出錯的乙個常見原因是:磁碟已寫滿,或者超過了對乙個給定程序的檔案長度限制。

lseek函式

#include 

#include

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

功能:設定檔案內容讀寫位置

返回:若成功為新的檔案位移,若出錯為- 1。

對引數offset 的解釋與引數whence的值有關。

看下面的例子:

#include 

#include

#include

#include

#include

char buf1 = "0123456789";

char buf2 = "abcdefghij";

int main(void)

先建立乙個新檔案file.hole,然後寫入10個位元組,再用lseek向後移動檔案位置指標30個位元組,這樣,中間的這30個位元組就是沒有任何資料的,然後在當前檔案位置指標處寫入10個位元組。這樣就產生了乙個檔案空洞。我們來看下它占有多少磁碟空間。

我們通過ls –hl 命令可以看到它占有50個位元組的磁碟空間,通過od命令(od -b 二進位制檢視)看出,中間30個位元組是0,而我們用cat命令來檢視,中間的30個位元組沒有顯示出來。這說明,空洞檔案是產生了,中間的30個位元組是不可見字元,沒有被顯示出來,而其在硬碟裡面卻真正的占用了30個位元組,空洞是否占用硬碟空間是由檔案系統(file system)決定的。

close函式

#include 

int close (int filedes);

功能:關閉乙個開啟檔案

返回:若成功為0,若出錯為- 1

當乙個程序終止時,它所有的開啟檔案都由核心自動關閉。很多程式都使用這一功能而不顯式地用close關閉開啟的檔案。

上面幾個系統呼叫的函式在我們的標準c裡基本上都有對應的函式實現,比如fopen對應open, fclose對應close, fread對應read, fwrite對應wirte。

下面再看乙個例子,標準c,與系統呼叫的區別:

#include 

#include

#include

int main(void)

分別用標準c的庫fopen和系統呼叫的open開啟兩個相同的檔案,這個檔案在我這兒是不存在的,分別列印出它們的出錯資訊和出錯號,和它們的檔案描述符和檔案指標。

系統呼叫open開啟出錯返回-1,而fopen返回型別是指標,因此返回是null,其型別是(void*)0,也就是0, 注意它們的出錯資訊,和錯誤號,都是一樣的,因為標準c的函式最終也是呼叫的系統呼叫實現其功能的。

《unix環境高階程式設計》筆記2

第四章 檔案和目錄 本章將描述檔案系統特徵和檔案性質 1 stat fstat和lstat函式 原型 include int stat const char restrict pathname,struct stat restrict buf int fstat int filedes,struct...

UNIX環境高階程式設計學習筆記

include include include include int main int argc,char argv err sys can t open s argv 1 while dirp readdir dp null printf s n dirp d name closedir dp ...

UNIX環境高階程式設計學習筆記(一)UNIX基礎知識

1.作業系統可被定義為一種軟體,它控制計算機硬體資源,提供程式執行環境。通常稱為核心 kernel 2.核心的介面被稱為系統呼叫。公共函式庫建在系統呼叫介面之上,應用程式既可使用公共函式庫,也可使用系統呼叫。shell是乙個特殊的應用程式,為執行其他應用程式提供乙個介面.3.unix檔案系統是目錄和...