溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

linux常用文件I/O操作之文件共享的實(shí)現(xiàn)方式

發(fā)布時(shí)間:2020-08-27 00:29:04 來源:網(wǎng)絡(luò) 閱讀:900 作者:捕風(fēng)的xiao_k 欄目:編程語言




 1、文件共享的三種實(shí)現(xiàn)方式

    1、什么是文件共享:   

    (1)文件共享就是同一個(gè)文件(同一個(gè)文件指的是同一個(gè)inode,同一個(gè)pathname)被多個(gè)獨(dú)立的讀寫體(幾乎可以理解為多個(gè)文件描述符)去同時(shí)(一個(gè)打開尚未關(guān)閉的同時(shí)另一個(gè)去操作)操作。

    (2)文件共享的意義有很多:譬如我們可以通過文件共享來實(shí)現(xiàn)多線程同時(shí)操作同一個(gè)大文件,以減少文件讀寫時(shí)間,提升效率。

    2、文件共享的核心就是怎么弄出來多個(gè)文件描述符指向同一個(gè)文件。

    3、常見的三種文件共享情況:

        1、是同一個(gè)進(jìn)程中多次使用open函數(shù)打開同一個(gè)文件。

        2、不同進(jìn)程中分別使用open函數(shù)打開同一個(gè)文件(因?yàn)榇藭r(shí)兩個(gè)fd不在同意進(jìn)程中,所以兩個(gè)fd可能相同,也可能不同)。

        3、linux提供的dup和dup2兩個(gè)API來讓進(jìn)程賦值文件描述符。

    4、我們分析文件共享的核心關(guān)注點(diǎn)在于:分別寫、讀還是連續(xù)讀寫

補(bǔ)充:

再論文件描述符:

    1、文件描述符的本質(zhì)是一個(gè)數(shù)字,這個(gè)數(shù)字本質(zhì)上是進(jìn)程表中文件描述符的一個(gè)表項(xiàng),進(jìn)程通過文件描述符作為index去索引查表得到文件表指針,再間接訪問得到這個(gè)文件對應(yīng)的文件表。

    2、文件描述符這個(gè)數(shù)字是open系統(tǒng)調(diào)用內(nèi)部由操作系統(tǒng)自動分配的,操作系統(tǒng)分配這個(gè)fd也不是隨機(jī)分配的,也會按照一定的規(guī)律。

    3、操作系統(tǒng)規(guī)定,fd從0開始一次增加,fd也是有最大限制的,在linux的早期版本中fd最大只有20.linux中文件描述符表是一個(gè)數(shù)組(而不是鏈表),所以這個(gè)文件描述符表其實(shí)就是一個(gè)數(shù)組,fd是index,文件表指針是value

    4、當(dāng)我們open時(shí),內(nèi)核會從文件描述符表中挑選一個(gè)最小的未被使用的數(shù)字給我們返回。

文件描述符的復(fù)制:

    5、fd中0、1、2已經(jīng)默認(rèn)被系統(tǒng)占用了,當(dāng)我們運(yùn)行一個(gè)程序得到一個(gè)進(jìn)程時(shí),內(nèi)部就默認(rèn)已經(jīng)打開了3個(gè)文件,這三個(gè)文件對應(yīng)的fd就是0、1、2。這三個(gè)文件分別叫stdin、stdout、stderr。也就是標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)錯誤。因此用戶進(jìn)程得到的最小的fd就是3了。

    6、標(biāo)準(zhǔn)輸入一般對應(yīng)的是鍵盤(可以理解為:0這個(gè)fd對應(yīng)的是鍵盤的設(shè)備文件),標(biāo)準(zhǔn)輸出一般是LCD顯示器(可以理解為:1對應(yīng)LCD的設(shè)備文件)

    7、printf函數(shù)其實(shí)就是默認(rèn)輸出到標(biāo)準(zhǔn)輸出stdout上了。stdio中還有一個(gè)函數(shù)叫fpirntf,這個(gè)函數(shù)就可以指定輸出到哪個(gè)文件描述符中。

2、如何實(shí)現(xiàn)文件共享

    1、同一個(gè)進(jìn)程中多次使用open函數(shù)打開同一個(gè)文件。同時(shí)打開同一個(gè)文件不難理解,關(guān)鍵在于打開同一個(gè)文件后,我們讀取寫入文件時(shí),是分別寫呢還是接續(xù)寫,簡單理解就是,覆蓋著寫呢?還是一個(gè)寫完了,文件指針自動挪到后邊分開寫?我們不用去猜,記別人的理論,我們直接自己用代碼測試,只要代碼正確的情況測試的結(jié)果就是理論。下來我們來看測試代碼:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<fcntl.h>
#include<string.h>


typedef int file_t;  
#define MAXLENG 1024

int main(int argc,char *argv[])
{
   file_t  fd1 = -1, fd2 = -1;
  	
   fd1 = open("./1.txt",O_RDWR | O_TRUNC | O_CREAT,0644);

   if(fd1 < 0)
   {
	   perror("fd1 :open file failed :");
	   _exit(-1);
   }

   fprintf(stdout,"fd1 = %d\n",fd1);
   
   
//這里為了區(qū)別更明顯,	fd2的open以及判斷完全可以放在fd1的判斷中去
   fd2 = open("./1.txt",O_RDWR | O_TRUNC | O_CREAT,0644);

   if(fd2 < 0)
   {
	   perror("fd2:open file fialed :");
	   _exit(-1);
    }

   fprintf(stdout,"fd2 = %d\n",fd2);

   while(1)
   {
	  
	   write(fd1,"aaaa",4);
	   sleep(1);
	   write(fd2,"bbbb",4);
   }
   
   return 0;

}

這段代碼運(yùn)行完成以后,我們來看結(jié)果

[root@xiao_k filetest]# cat 1.txt 
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaa[root@xiao_k filetest]#

    這樣我們可以很容易看到,我們雖然是用兩個(gè)文件指針分別寫,但是fd1只有在最后一次寫進(jìn)去,對吧?這時(shí)我們看到的;但是這為什么會這樣呢?這里我們分析一下:其實(shí)fd1進(jìn)行了寫入操作,只是我們fd1和fd2兩個(gè)文件指針是不同的文件指針,當(dāng)fd1寫入以后,文件指針往后移動,但是fd2并沒有移動,當(dāng)fd2進(jìn)行寫入時(shí)就會覆蓋掉fd1寫入的內(nèi)容,并且這里與你兩次打開文件的屬性有關(guān),這里使用

O_RDWR | O_TRUNC | O_CREAT三個(gè)屬性打開,我們也可以自己測試其他屬性打開的結(jié)果。雖然不同屬性打開的結(jié)果可能造成的結(jié)果不同,但是我們這里是可以確定的,一個(gè)文件指針移動后并不會造成另外一個(gè)文件指針移動。

    2、第二種方法用不同進(jìn)程中分別使用open函數(shù)打開同一個(gè)文件(因?yàn)榇藭r(shí)兩個(gè)fd不在同意進(jìn)程中,所以兩個(gè)fd可能相同,也可能不同)。這里還沒有總結(jié)fork函數(shù)產(chǎn)生新的進(jìn)程。所以先不總結(jié),博主后邊補(bǔ)充上去。


    3、使用linux提供的dup和dup2兩個(gè)API來讓進(jìn)程賦值文件描述符。

     1、使用dup進(jìn)行文件描述符復(fù)制

      (1)dup系統(tǒng)調(diào)用對fd進(jìn)行復(fù)制,會返回一個(gè)新的文件描述符(譬如原來的fd是3,返回的就是4)

      (2)dup系統(tǒng)調(diào)用有一個(gè)特點(diǎn),就是自己不能指定復(fù)制后得到的fd的數(shù)字是多少,而是由操作系統(tǒng)內(nèi)部自動分配的,分配的原則遵守fd分配的原則。

      (3)dup返回的fd和原來的oldfd都指向oldfd打開的那個(gè)動態(tài)文件,操作這兩個(gè)fd實(shí)際操作的都是oldfd打開的那個(gè)文件。實(shí)際上構(gòu)成了文件共享。

      (4)dup返回的fd和原來的oldfd同時(shí)向一個(gè)文件寫入時(shí),結(jié)果是分別寫還是接續(xù)寫?

使用dup的缺陷分析

      (1)dup并不能指定分配的新的文件描述符的數(shù)字,dup2系統(tǒng)調(diào)用修復(fù)了這個(gè)缺陷,所以平時(shí)項(xiàng)目中實(shí)際使用時(shí)根據(jù)具體情況來決定用dup還是dup2.

     2、使用dup2進(jìn)行文件描述符復(fù)制

      (1)dup2和dup的作用是一樣的,都是復(fù)制一個(gè)新的文件描述符。但是dup2允許用戶指定新的文件描述符的數(shù)字。

      (2)使用方法看man手冊函數(shù)原型即可。

測試使用dup和dup2共享文件操作:

    1、dup共享文件的實(shí)現(xiàn)

    

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
#include<errno.h>

typedef int file_t;
#define MAXSIZE 1024

int main(int argc,char *argv[])
{
	file_t fd1 = -1, fd2 = -1;
	fd1 = open("./3.txt",O_RDWR | O_CREAT | O_TRUNC,0644);

	if(fd1 < 0)
	 {
		perror("open fiel error :");
		_exit(-1);
	}
	
	fprintf(stdout,"fd1 = %d\n",fd1);

	fd2 = dup(fd1);

	if(-1 == fd2)
	{
		perror("dup error:");
		_exit(-1);
 	}

	fprintf(stdout,"fd2 = %d\n",fd2);

	while(1)
	{
		write(fd1,"aaaa",4);
		sleep(1);
		write(fd2,"bbbb",4);
	
	}



	return 0;
}

我們繼續(xù)來看結(jié)果:

[root@xiao_k filetest]# cat 3.txt 
aaaabbbbaaaabbbbaaaabbbbaaaabbbbaaaabbbbaaaabbbbaaaabbbbaaaabbbbaa
aabbbbaaaabbbbaaaabbbbaaaabbbbaaaabbbbaaaabbbbaaaabbbbaaaabbbbaaaa
[root@xiao_k filetest]#

     從結(jié)果我們這次可以發(fā)現(xiàn)a和b是交替出現(xiàn)的,這也符合預(yù)期,dup雖然是產(chǎn)生了兩個(gè)文件描述符,但是共用同一個(gè)文件指針,當(dāng)一個(gè)寫入以后,文件指針已經(jīng)移動到后邊去,自然不會覆蓋掉了。


   2、dup2共享文件交叉寫入測試

    1、對于dup2和dup寫入文件一樣,區(qū)別在于dup2可以自己指定文件描述符,所以這里就不給出dup2寫入文件的實(shí)例。

    2、交叉寫入的時(shí)候,結(jié)果是接續(xù)寫

3、fcntl函數(shù)

    1、fcntl函數(shù)是一個(gè)多功能文件管理的工具箱,可以接受2個(gè)參數(shù)+1個(gè)變參,第一個(gè)參數(shù)是fd表示喲啊操作那個(gè)文件,第二個(gè)參數(shù)是cmd表示要進(jìn)行那個(gè)命令操作。變參是用來傳遞參數(shù)的,要配合cmd命令使用

    2、cmd的樣子類似于F_XXX,不同的cmd具有不同的功能。學(xué)習(xí)時(shí),沒有必要把所有的cmd含義弄清楚,只需要把一個(gè)弄明白就行,其他的查man手冊即可。

    3、常用fcntl的cmd    

      1、F_DUPFD這個(gè)cmd的作用是復(fù)制文件描述符(作用類似于dup和dup2),這個(gè)命令的功能是從可用的fd數(shù)字列表中找一個(gè)比arg大或者和arg一樣大的數(shù)字作為oldfd的一個(gè)復(fù)制的fd,和dup2有點(diǎn)像但是不同。dup2返回的就是我們指定的那個(gè)newfd否則就會出錯,但是F_DUPFD命令返回的是>=arg的最小的那一個(gè)數(shù)字。

4、標(biāo)準(zhǔn)I/O庫

  1、標(biāo)準(zhǔn)IO和文件IO有什么區(qū)別

    1、最大的區(qū)別:標(biāo)準(zhǔn)I/O庫是C庫函數(shù),而文件I/O是linux系統(tǒng)調(diào)用的API

    2、C語言庫函數(shù)是由API封裝起來的,庫函數(shù)內(nèi)部也是通過調(diào)用API來完成操作的,但是庫函數(shù)多了一層封裝,所以比API更加好用。

    3、庫函數(shù)比API還有一個(gè)優(yōu)勢,API在不同的操作系統(tǒng)的接口是不一樣的是不能通用的,但是C庫函數(shù)在不同操作系統(tǒng)上幾乎是一樣的,所以C庫函數(shù)具有可移植性而API不具有可移植性。

   2、常用標(biāo)準(zhǔn)IO函數(shù)介紹:

        常見的標(biāo)準(zhǔn)IO庫函數(shù):fopen fclose fwrite fread ffulsh、fseek


    以上文檔,本人學(xué)習(xí)參考了不同老師的文檔自己總結(jié)而來,代碼都是本人親自測試。關(guān)于文檔那塊有問題,請各位指正。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI