UNIX環境下文件IO

概述

大多數UNIX文件IO只需用到5個函數:open、read、write、lseek以及close。這些函數經常被稱之爲不帶緩存的IO,不帶緩存指的是每個read和write都調用內核中的一個系統調用。

文件空洞

當文件偏移量跨越了文件結尾時執行IO操作,read()調用會返回0,write()調用可以在文件結尾後的任意位置寫入數據,對該文件的下一次寫入將延長文件,並在文件中構成一個空洞。從原來的文件結尾到新寫入數據間的這段空間稱爲文件空洞。在文件空洞中寫入數據,文件系統會爲之分配磁盤塊。下面給出創建文件空洞的例子。

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include "ourhdr.h"
 

int main(int argc,char **argv)
{
    char          buf1[]="abcdefghijkl";
    char          buf2[]="ABCDEFG";
    int           fd=-1;
    off_t         offset=0;

    if((fd=creat("file.hole",FILE_MODE)) < 0)//創建一個文件
    {
        printf("creat failure: %s\n",strerror(errno));
    }

    if(write(fd,buf1,sizeof(buf1)) < 0)//向該文件中寫buf1
    {
        printf("buf1 is writed  failure: %s\n",strerror(errno));
    }

    if((offset=lseek(fd,40,SEEK_SET)) == -1)//文件偏移40
    {
        printf("lseek failure: %s\n",strerror(errno));
    }
    else 
    {
        printf("Current lseek: %ld\n",offset);
    }

    if(write(fd,buf2,sizeof(buf2)) < 0)//偏移之後再寫入buf2
    {
        printf("buf2 is writed failure: %s\n",strerror(errno));
    }

    return 0;

    
}

運行並查看文件
在這裏插入圖片描述-c:表示以字符方式打印文件內容
lseek函數只修改文件表項中的當前文件位移量,並沒有進行io操作,文件偏移從文件開頭開始。圖中\0所示的空間就是文件空洞。

文件共享

linux下用戶級別一個進程默認可以打開1024個文件描述符,在進行高併發的時候往往存在限制,這時候可以通過修改文件配置更改限制,比如:
在這裏插入圖片描述假如,我們設置進程打開的文件句柄數是1024 ,但是系統總線制才500,所以所有進程最多能打開文件句柄數量500。從這裏我們可以看出只設置進程的打開文件句柄的數量是不行的。所以需要修改系統的總限制纔可以,比如:

在這裏插入圖片描述

一個進程打開多個文件

在這裏插入圖片描述

兩個進程打開同一個文件

在這裏插入圖片描述

原子操作

當多個進程寫同一文件時,則可能產生預期不到的結果。爲了說明如何避免這種情況,需要了解原子操作的概念。

所謂原子操作,如果這個操作所處的層的更高層不能發現奇內部實現與結構,那麼這個操作就是一個原子操作。原子操作可以是一個步驟,也可以是多個步驟,但是其順序不可以被打斷,也不可以被切割而執行其中的一部分,將整個操作視作一個整體。

例子1
兩個進程同時向一個文件寫入數據時,如果A進程和B進程都調用lseek該增加1500偏移量,而後B進程寫入數據文件時文件偏移量增加了1600偏移量,此時內核對V結點中的當前文件長度更新爲1600,然後A進程開始運行時將從文件偏移量1500處將數據寫入,那麼進程B些入的數據將被替換,這不是我們想要的,爲了避免這種情況發生,O_APPEND標誌的設置就是一種原子操作。

例子2
多個進程創建一個文件並向其中寫入數據時,發生數據被覆蓋的現象。那麼open函數的O_CREATE和O_EXCL就是原子操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章