檔案I/O(2)

來源:互聯網
上載者:User

檔案I/O(2)檔案分享權限設定

核心使用三種資料結構表示開啟的檔案,他們之間的關係決定了在檔案分享權限設定方面一個進程對另一個進程可能產生的影響。1所示。

1) 每個進程在進程表中都有一個記錄項,記錄項中包含一張開啟檔案描述表,可將其視為一個向量,每個描述符佔用一項。與每個檔案描述符相關聯的是:

a) 檔案描述符標誌

b) 指向一個檔案表項的指標

2) 核心為所有開啟檔案維持一張檔案表。每個檔案表項包含:

a) 檔案狀態標誌(讀、寫、讀寫、添些、同步和阻塞等)

b) 當前檔案位移量

c) 指向檔案v節點表項的指標

3) 每個開啟檔案(或裝置)都有一個v節點(v-node)結構。v節點包含了檔案類型和對比檔案進行各種操作的函數的指標。對於大多數檔案,v節點還包含了該檔案的i節點。i節點包含檔案所有者、檔案長度、檔案所在的裝置、指向檔案實際資料區塊在磁碟上所在位置的指標等。

如果兩個進程各自開啟了同一個檔案,則2所示。假定第一個進程在檔案描述符3開啟上該檔案,而另一個進程在檔案描述符4上開啟該檔案。每個進程都得得到一個檔案表項,但對一個給定的檔案只有一個v節點表項。每個進程都有自己的檔案表項的一個理由是:使每個進程都有自己對該問價的當前位移量。

現在對前一節檔案I/O(1)的幾個操作進一步說明:

1. 完成write之後,檔案中當前位移量即所增加的位元組數。如果當前位移量大於檔案長度,則將i節點中當前檔案長度設為當前檔案位移量。

2. 用O_APPEND開啟一個檔案,相應標誌會被設定到檔案狀態標識中。每次寫時,當前位移量會被設定為i節點中的檔案長度

3. lseek定位到檔案尾端時,則檔案當前位移量會被設定為當前檔案長度。

可能有多個檔案描述符指向同一檔案表項。調用dup和fork時都能看到這一點。

多個進程讀同一檔案能正確工作。但多個進程寫同一檔案時,可能產生預期不到的後果。可以利用原子操縱避免這種情況。

原子操作

一般而言,原子操作指的是由多部組成的操作。如果該院自地執行,要麼執行完所以步驟,要麼一步也不執行。

1. 添加至一個檔案

考慮一個進程,它要講資料添加到一個檔案尾端。早期UNIX不支援open,所以可以如下實現:

if(lseek(fd, 0L, 2)<0)

err_sys(“lseekerror”);

if(write(fd, buf, 100) != 100)

err_sys(“writeerror”);

對於單個進程,這段程式能正常工作。但多個進程就不一定。結社進程A和B都對同一檔案進行添加操作。每個進程都開啟該檔案,此時資料結構之間關係2中所示。假定A調用lseek,將A的當前位移量設定為1500。進程B執行lseek也將其當前位移量設為1500。然後B調用write,將當前位移量增至1600。然後核心又進行進程切換使進程A恢複運行,當A調用write時,從其當前位移量1500處將資料寫入,將替換B剛寫入到該檔案中的資料。

問題出在邏輯操作“定位到檔案尾端處,然後寫“使用了兩個分開的函數調用。解決辦法是使這兩個操作成為一個原子操作。O_APPEND標識,使核心每次對檔案進行寫之前,都將進程當前位移量設定到該檔案的尾端處。

2.pread和pwrite函數

原子性地定位搜尋和執行I/0。

#include <unistd.h>

ssize_t pread(int fd, void *buf, size_tcount, off_t offset);

ssize_t pwrite(int fd, const void *buf,size_t count, off_t offset);

ssize_t pread(int fd, void *buf, size_tcount, off_t offset);

ssize_t pwrite(int fd, const void *buf,size_t count, off_t offset);

dup和dup2函數

#include <unistd.h>

int dup(int oldfd);

int dup2(int oldfd, int newfd);

上面兩個函數都可用來複製一個現存的檔案描述符。

由dup返回的新檔案描述符一定是當前可用檔案描述符中的最小數值。用dup2則可以用newfd參數指定新描述符的數值。如果newfd已經開啟,則先將其關閉。如果newfd等於oldfd,則dup2返回newfd而不關閉它。

圖3.3顯示了這種情況。

假定我們的進程執行了:

newfd = dup(1);

當此函數執行時,假設下一個可用的描述符是3。因為這兩個描述符指向同一個檔案表項,所以他們共用檔案標誌以及同一檔案位移量。

sync、fsync和fdatasync

#include <unistd.h>

void sync(void);

int fsync(int fd);

int fdatasync(int fd);

當將資料寫入檔案時,核心通常將資料複製到一個緩衝區,直到緩衝區寫滿,再將緩衝區排路輸出隊列,然後等待其到達隊首,才進行實際的I/O操作。這種輸出防暑被稱為延遲寫。延遲寫減少了磁碟的讀寫次數,但卻降低了檔案內容的跟新速度。當系統發生故障時,延遲寫可能造成檔案跟新內容的丟失。為了保證磁碟上實際檔案系統與緩衝區快取中內容一致性,UNIX系統提供了sync、fsync和fdatasync 三個函數。

fcntl函數

#include <unistd.h>

#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */ );

可以改變已經開啟檔案的性質。

複製一個現有的描述符(cmd=F_DUPFD)
獲得或設定檔案描述符(cmd=F_GETFD|F_SETFD)
獲得或設定檔案狀態標誌(cmd=F_GETFL|F_SETFL)
獲得或設定非同步I/O所有權(cmd=F_GETOWN|F_SETOWN)
獲得或設定記錄鎖(cmd=F_GETLK|F_SETLK、F_SETLKW)

可以用fcntl函數設定檔案狀態,常用設定通訊端描述符為非阻塞O_NONBLOCK

ioctl函數

#include <sys/ioctl.h>

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

提供了一個用於控制裝置及其描述符行為和配置底層服務的介面。

/dev/fd

開啟檔案/dev/fd/n等效於複製描述符n。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.