C語言檔案與目錄(五)檔案鎖

loophome發表於2015-11-06

1)檔案鎖定

所謂的檔案鎖定,指的是以獨佔的方式開啟檔案。一個程式開啟檔案以後,其它的程式不能讀取或寫入檔案。檔案鎖定有利於檔案內容的一致性。本節將講解檔案的鎖定許可權問題。

檔案鎖定的理解:當多個程式程式同一個檔案時,可能導致檔案的內容不一致情況。例如一個檔案中的資料是一個賬戶金額。使用者開啟這個檔案讀取資料,進行處理以後將寫結果寫入到檔案。如果檔案沒有進行鎖定時,可以發生下面這種錯誤。
(1)假設定檔案中的資料為10000。使用者A開啟檔案讀取這個資料,讀取了這個資料。但是還沒有及時的寫入。
(2)這時,使用者B讀取這個資料,將結果加10000。然後將結果20000寫入到這個檔案。
(3)使用者A的處理時間較長,比使用者B早讀入資料,但後寫入資料。A將資料加1000,得到11000,然後將資料寫入到檔案。
這時就發生了一個錯誤,使用者B的資料丟失。這時需要在開啟檔案時進行檔案鎖定,正確的做法如下所示。
(1)假設定檔案中的資料為10000。使用者A開啟檔案讀取這個資料,讀取了這個資料。但是還不能及時的寫入,於是將檔案加一把鎖,不允許別的使用者訪問。
(2)使用者B訪問這個檔案時,檔案已經加鎖,無法訪問。於是等待使用者A完成資料訪問。
(3)使用者A完成資料處理以後,將資訊寫入到檔案,這時解除對檔案的鎖定。
(4)這時使用者B可以對檔案進行訪問。訪問的同時,對檔案新增一個鎖定。在解除鎖定以前,其他的使用者不能訪問這個檔案。


檔案鎖定函式flock:在訪問一個檔案時,可以用flock函式對檔案進行鎖定。防止其他使用者同時訪問這個檔案發生資料不一致的情況。這個函式的使用方法如下所示。
int flock(int fd,int operation);
在引數列表中,fd是open函式開啟檔案時返回的開啟序號。operation是系統定義的一些整型常量,可能的取值和含義如下所示。
LOCK_SH:建立共享鎖定,其他的程式可以同時訪問這一個檔案。多個程式可同時對同一個檔案作共享鎖定。
LOCK_EX:建立互斥鎖定,其他使用者不能同時訪問這一個檔案。
注意:一個檔案同時只有一個互斥鎖定。單一檔案不能同時建立共享鎖定與互斥鎖定。
LOCK_UN:解除檔案鎖定狀態。
LOCK_NB:無法建立鎖定時,此操作可不被阻斷,馬上返回程式。通常與LOCK_SH或LOCK_EX 做OR(|)組合。
當檔案鎖定成功時,會返回0,否則返回-1。可以用errno來捕獲發生的錯誤。這個函式可能發生的錯誤如下所示。
EBADF:fd引數不是一個已經開啟的檔案。
EINTR:在進行操作時,這個操作被其他的程式或訊號所中斷。
EINVAL:給入的引數不合法。
ENOLCK:核心記憶體溢位錯誤。
EWOULDBLOCK:這個已經被其他程式建立互斥鎖定。

DEMO:

int fd_lock;
char file_lock[255]="";
strcat(strcpy(file_lock,mainpath),"\\file_lock.txt");
if((fd_lock=open(file_lock,O_RDONLY))!=0)
{
	if(flock(fd_lock,LOCK_EX)==0)
	{
		printf("%s %s\n",file_lock,"locked!");
	}
	else
	{
		printf("%s\n",strerror(errno));
	}
	close(fd_lock);
}

2)檔案某一部分鎖定

檔案鎖定函式fcntl:函式fcntl的作用是對一個檔案進行鎖定。與flock函式不同的是,fcntl可以設定對檔案的某一部分進行鎖定。
該函式的使用方法如下所示。
int fcntl(int fd , int cmd);
int fcntl(int fd,int cmd,long arg);
int fcntl(int fd,int cmd,struct flock *lock);
這個函式的引數列表有多種形式。在編譯時,會自動與引數進行匹配。引數fd是open函式開啟檔案時返回的檔案編號。cmd是系統定義的一些整型常量,用來設定檔案的開啟方式,有下面幾種可選方式。
F_DUPFD:用來查詢大於或等於引數arg的最小且仍未使用的檔案編號,並且複製引數fd的檔案編號。執行成功則返回新複製的檔案編號。
F_GETFD:取得close-on-exec標誌。若此標誌的引數arg 的FD_CLOEXEC位為0,代表在呼叫exec()相關函式時檔案將不會關閉。
F_SETFD:設定close-on-exec 旗標。該旗標以引數arg的FD_CLOEXEC位決定。
F_GETFL:取得檔案描述詞狀態旗標,此旗標為open的引數返回序號。
F_SETFL: 設定檔案描述詞狀態旗標,引數arg為新旗標,但只允許O_APPEND、O_NONBLOCK和O_ASYNC位的改變,其他位的改變將不受影響。
F_GETLK:取得檔案鎖定的狀態。
F_SETLK:設定檔案鎖定的狀態。此時flcok 結構的l_type 值必須是F_RDLCK、F_WRLCK或F_UNLCK。如果無法建立鎖定,則返回-1,錯誤程式碼為EACCES 或EAGAIN。
F_SETLKW或F_SETLK :這兩個引數的作用相同,但是無法建立鎖定時,此呼叫會一直等到鎖定動作成功為止。
引數lock指標為flock型別的結構體指標,用來設定鎖定檔案的一個區域。flock結構體的定義方式如下所示。
01 struct flock
02 {
03   short int l_type;/*檔案的鎖定狀態。*/
04   short int l_whence;/*設定l_start位置。*/
05   off_t l_start;/*鎖定區域的開頭位置,從這個地方開始鎖定檔案的內容。*/
06   off_t l_len;/*鎖定檔案區域的大小。*/
07   pid_t l_pid;/*鎖定檔案的程式。*/
08 };

l_type 有下面三種可選的引數。
F_RDLCK:建立一個供讀取用的鎖定。
F_WRLCK:建立一個供寫入用的鎖定。
F_UNLCK:刪除之前建立的鎖定方式。
l_whence 有下面的三種可選設定方式。
SEEK_SET:以檔案開頭為鎖定的起始位置。
SEEK_CUR:以檔案當前的讀寫位置為鎖定的起始位置。
SEEK_END:以檔案結尾為鎖定的起始位置。
fcntl函式執行成功則返回0,失敗則返回-1。這個函式可能發生下面的錯誤,可以用errno來捕獲發生的錯誤。
EACCES或EAGAIN:檔案已經被鎖定,沒有許可權再進行鎖定操作。
EAGAIN:檔案已經被另外一個程式佔用。
EBADF:df引數無效或檔案已經關閉。 
EDEADLK:這個檔案被死鎖。
EFAULT:檔案處於只讀的分割槽內。
EINTR:操作被其他的程式或訊號中斷。
EINVAL:函式所給的引數不合法。
EMFILE:已經超過了最多可以開啟的檔案數。
ENOLCK:已經建立了太多的鎖定方式。
EPERM:在以追加方式開啟的檔案上錯誤的進行鎖定。
在使用這個函式時,需要在程式的最前面包含下面的標頭檔案。
#include <unistd.h>
#include <fcntl.h>


相關文章