unix下C標準檔案操作及程序相關知識

2021-06-19 17:54:20 字數 3985 閱讀 9636

close函式可以關閉乙個已開啟的檔案

#include

int close(int fd);//返回值:若成功返回0;若出錯,返回-1並設定errno

引數fd是要關閉的檔案描述符,需要說明的是,當乙個程序終止時,核心對該程序所有尚未關閉的檔案描述符呼叫close(fd)函式關閉,所以即便使用者程式不呼叫close,在終止時核心也會自動關閉它開啟的所有檔案,但是對於乙個長年累月執行的程式(比如網路伺服器),開啟的檔案描述符一定要記得關閉,否則隨著檔案開啟的越來越多,會占用大量檔案描述符和系統資源。

有open函式返回的檔案描述符一定是該程序尚未使用的最小描述符,由於程式啟動時自動開啟檔案描述符0.1.2,因此第一次呼叫open開啟檔案通常會返回描述符3,再呼叫open就會返回4,可以利用這一點在標準輸入,標準輸出,或標準錯誤輸出上開啟乙個新檔案,實現重定向的功能,例如,首先呼叫close關閉檔案描述符1,然後呼叫open開啟乙個常規檔案,則一定會返回檔案描述符1,這時標準輸出就不再是終端,而是乙個常規檔案了,再呼叫printf就不會列印到螢幕上,而是寫到這個檔案中了。

讀常規檔案是不會阻塞的,不管讀多少位元組,read一定會在有限時間內返回,但是從終端裝置或網路讀則不一定,如果從終端輸入的資料沒有換行,呼叫read讀終端裝置時就會阻塞,如果網路上沒有接收到資料報,呼叫read從網路上讀就會阻塞,至於會阻塞多長時間也是不確定的,如果一直沒有資料到達就一直阻塞在**,寫常規檔案是不會阻塞的,而向終端或網路裝置寫則不一定,。

fcntl

先前我們以read終端裝置為例介紹了非阻塞的i|o,為什麼我們不直接對stdin_fileno做非阻塞read而是要重新open以便/dev/tty。因為stdin_fileno在程式啟動時已經被自動開啟了,而且我們需要在呼叫open時指定o_nonblock標誌,這裡介紹另外一種辦法,可以用fcntl函式改變乙個已開啟的檔案的屬性,可以重新設定讀、寫、追加、非阻塞等標誌(這些標誌稱為file status flag),而不必重新open檔案

函式原型為

#include

#include

int fcntl;

int fcntl(int fd,int cmd,long arg);

int fcntl(int fd,int cmd,struct flock*lock);

這個函式和open一樣,使用可變引數來實現的,可變引數的型別和個數取決於前面的cmd引數,下面的例子使用f_getfl和f_setfl這兩種fcntl命令改變stdin_fileno的屬性,。

ioctl用於向裝置發控制和配置命令,有些命令也需要讀寫一些資料,但是這些資料是不能用read|write讀寫的,稱為out-of-band資料,也就是說,read|write讀寫的資料是in-band資料,是i|o操作的主體,而ioctl命令傳送的是控制資訊,其中的資料是輔助的資料,例如,在串列埠線上收發資料通過read|write操作,而串列埠的波特率、校驗位、停止位通過ioctl設定,a|d轉換的結果是通過read讀取,而a|d轉換的精度和工作的頻率通過ioctl設定。

其函式原型為:

#include

int ioctl(int d,int request,.....);

d是某個裝置的檔案描述符,request是ioctl的命令,可變引數取決於request,通常是乙個指向變數或結構體的指標,若出錯則返回-1,若成功則返回其他值,返回值取決於request

我們知道,每個程序在核心內都有程序控制塊(pcb)來維護程序相關的資訊,linux核心的程序控制塊是task_struct結構體,現在我們來了解其中有哪些資訊。

可以形象地描述為

程序id,系統中每乙個程序都有唯一的id。在c語言中用pid_t型別來表示,其實就是乙個非負的整數。

程序的狀態,有執行、掛起、停止、殭屍等。

程序切換時需要儲存和恢復一些cpu暫存器。

描述虛擬位址空間的資訊。

描述控制終端的資訊。

當前工作目錄

umask掩碼

檔案描述符表,包括很多指向file結構體的指標

和訊號有關的資訊

使用者id和組id

控制終端、session和程序組

程序可以使用的資源上限

環境變數

先前講過,exec系統呼叫執行新程式時會把命令列引數和環境變數表傳遞給main函式,它們在整個程序位址空間中的位置如下圖所示

和命令列引數argv類似,環境變數表也是一組字串。libc中定義的全域性變數environ指向環境變數表,environ沒有包含在任何標頭檔案中,所以在使用時要用extern宣告。

path可執行檔案的搜尋路徑,ls也是乙個程式,執行它時 不需要提供完整的路徑名/bin/ls。然而通常我們執行當前目錄下的程式a.out卻需要提供完整的路徑名./a.out,這是因為path環境變數的值裡面包含有ls命令所在的目錄/bin.卻不包含a.out所在的目錄,path環境變數的值可以包含多個目錄,用:號隔開

父程序在建立子程序時會複製乙份環境變數給子程序,但是此後兩者之間的環境變數互不影響

fork函式

乙個現有程序可以呼叫fork函式建立乙個新程序

#include

pid_t fork(void);

由fork建立的新程序被稱為子程序,fork函式被呼叫一次,但返回兩次,兩次返回的唯一區別是子程序的返回值為0,而父程序的返回值為新子程序的程序id

下面介紹乙個例子

char*message;

int n;

pid=fork();

if(pid<0)

perror("fork failed");

exit(1);

if(pid==0)

message="this is the child\n";

n=6;

else

message="this is the parent\n";

n=3;

for(;n>0;n--)

printf(message);

sleep(1);

fork呼叫把父程序的資料複製乙份給子程序,但此後;兩者互不影響,在這個例子中,fork呼叫之後父程序和子程序的變數message和n被賦值不同的值,互不影響(子程序只是得到父程序的副本,並不共享儲存空間。)

wait和waitpid函式

乙個程序在終止時會關閉所有檔案描述符,釋放在使用者空間分配的記憶體,但是它的pcb還保留著,核心在其中的儲存了一些資訊,但是他的pcb仍然會保留著,核心在其中儲存了一些資訊:如果是正常終止則儲存著退出狀態,如果是異常終止則儲存著導致該程序終止的具體訊號,這個程序的父程序可以呼叫wait或waitpid獲取這些資訊,然後徹底的清除掉這個資訊,我們知道乙個程序的退出狀態可以再shell中用特殊變數檢視,因為shell是它的父程序,當它終止時shell呼叫wait或waitpid得到它的退出狀態同時徹底清除掉這個程序,

如果乙個程序已經終止,但是它的父程序尚未呼叫wait或waitpid對它進行清理,這時的程序狀態被稱為殭屍程序,任何程序在剛終止時都是殭屍程序,在正常情況下,殭屍程序都是立即被父程序清理的。為了觀察殭屍程序,我們自己寫乙個不正常的程式,父程序fork出子程序,子程序終止,而父程序既不終止也不呼叫wait清理子程序

殭屍程序不能用kill命令來清除掉的,因為kill命令只是用來終止程序你的,而殭屍程序已經種植呢了。

注釋:(

libc是linux下的ansi c的函式庫。ansi c是基本的c語言函式庫,包含了c語言最基本的

庫函式。這個庫可以根據 標頭檔案劃分為 15 個部分,其中包括:字元型別 ()、

錯誤碼 ()、 浮點常數 ()、數學常數 ()、標準定義 ()、 標準 i/o ()、工具函式 ()、字串操作 ()、 時間和日期 ()、可變參數列 ()、訊號 ()、 非區域性跳轉 ()、本地資訊 ()、程式斷言 () 等等。這在其他的c語言的ide中都是有的。

每個程序都可以通過乙個特殊的裝置檔案/dev/tty訪問它的控制終端,事實上每個終端裝置都對應乙個不同的裝置檔案,/dev/tty提供了乙個通用的介面,乙個程序要訪問它的控制終端既可以通過/dev/tty也可以通過該終端裝置對應的裝置檔案來訪問,ttyname函式可以由檔案描述符查出對應的檔名,該檔案描述符必須指向乙個終端裝置,而不是人任意的檔案,

高階檔案程式設計 標準檔案操作的函式

高階檔案程式設計 標準檔案操作的函式 本節所講的檔案讀寫函式均是指順序讀寫,即讀寫了一條資訊後,指標自動 加1。下面分別介紹寫操作函式和讀操作函式。1.檔案的順序寫函式 fprintf fputs 和fputc 函式 函式fprintf fputs 和fputc 均為檔案的順序寫操作函式,其呼叫格 ...

Unix標準IO檔案流及緩衝型別

在檔案io相關函式的一節中,我們所有的i o函式都是圍繞著檔案描述符來操作的,當開啟乙個檔案的時候,即返回乙個檔案描述符,然後該檔案描述符用於後續的檔案操作。而對於標準io庫,對於檔案的操作都是圍繞這 檔案流 file stream 進行的。當我們使用標準io庫開啟或建立乙個檔案的時候,我們已經使乙...

C語言及程式設計高階例程 35 標準檔案讀寫方法

賀老師教學鏈結 c語言及程式設計高階 本課講解 示例 以字元為單位複製檔案 複製檔案a.txt,儲存到b.txt中 include include int main if fp2 fopen b.txt w null 開啟用於寫入的目標檔案 while ch fgetc fp1 eof 從原始檔中逐...