Unix文件操做

1、概述node

Unix文件操做經常使用函數包括openclosecreatlseekdupdup2fcntl等,編程

其中open、creat、 fcntl函數須要包含頭文件<fcntl.h>,緩存

其他幾個函數須要包含頭文件<unistd.h>。網絡

因爲在Linux操做系統 中使用man命令能夠很是方便的查找函數原型及示例,這裏就不帖出函數原型了,只講一下使用時須要注意的地方。多線程

2、文件描述符app

每個在程序中打開的文件都有一個相應的文件描述符(file descriptor),Unix操做系統中的文件描述符保存在/dev/fd目錄下。async

每個進程對該目錄讀取到的結果都不想同(視該進程正在使用的文件 數而定)。函數

若是由open函數直接讀取該路徑下的文件,將視爲在此進程中對該文件描述符所對應的文件進行dup操做,在大多數操做系統中將忽略打開方式, 而部分操做系統要求打開方式爲所涉及文件原先打開方式的子集。ui

3、Flagsspa

當使用O_APPEND方式打開文件時,每次調用write函數會在文件最後面寫入新數據,調用write函數後讀取當前文件偏移量 (current offset)能夠很清楚的看到該值與文件最大偏移量相等。

若是使用了O_RDWR | O_APPEND方式打開文件,程序能夠對該文件在任意位置實現讀取操做(read),但寫入操做(write)會使文件偏移量被重置,若是讀取與寫入混 合使用,可能會致使讀取位置出現誤差。

4、函數細說

4. 1 creat & open  

  creat函數與

open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode);

  等同,使用creat函數的缺陷在於若是須要在建立的同時讀寫該文件,須要在建立後將文件關閉,從新以讀寫方式open該文件,相對而言,下面的調用方式更爲簡單:

open(pathname, O_RDWR | O_CREAT | O_TRUNC, mode);

  其中,O_TRUNC表示:若是此文件存在,並且爲只讀或只寫成功打開,則將其長度截短爲0(即會清空文件內容)

4.2 lseek

  在lseek函數中,偏移量(offset)是一個長整型,可正可負。若是偏移量大於文件最大偏移量,對該位置進行寫入操做,將對文件進行擴展,文件中的空洞(從原文件最大偏移量到寫入位置)被填充爲0,但並不佔用磁盤塊

  例如:

fd = creat("file.txt", S_IRWXU);
lseek(fd,102400,SEEK_SET);
write(fd,"abcdefg",7);

  程序執行後,使用"ls -ls file.txt"命令能夠看出,文件file.txt所佔塊數爲8.

 4.3 read

  使用read函數時,遇到如下狀況會使read函數提早返回:

  • 文件讀取遇到EOF。
  • 從終端中讀取到一行內容。(STDIN_FILENO)
  • 當從網絡讀時,網絡中的緩衝機構可能形成返回值小於所要求讀的字節數。
  • 從管道或FIFO中讀取到所有內容。
  • 某些面向記錄的設備,例如磁帶,一次最多返回一個記錄。
  • 接收到中斷信號。

5、File Sharing

5.1 說明

  在進程中,一個進程所打開的全部文件描述符存放在一個table中,table中的每條記錄包括文件描述符falgs(file descriptor flags)和指向文件表的指針(fils pointer)。

  一個文件表包含一個文件的狀態標誌(file status flags),當前偏移量(offset),一個指向v-node表的指針。一個v-node表包括v-node信息,i-node信息,文件大小等。如 圖1所示:

圖1. Unix文件表(進程中)

  在多個進程中,可能出現多個文件描述符指向同一個文件,此時如圖2所示:

圖2. 多個進程中同時打開同一個文件

  當使用dup、dup2函數後,文件描述符將被複制,此時如圖3所示:

圖3. dup後多個文件描述符指向同一個file table

5.2 控制多進程對文件的訪問

  在進行多進程或多線程編程時,因爲沒法控制CPU對進程和線程的調度,若是不加以控制,可能會在任意兩條程序控制語句中間出現中斷,致使數據被污染。

  可使用原語來保證在特定操做中數據不會被污染,使數據同步。

  原語形式的文件讀寫函數爲 pread和pwrite。

  也正由於數據可能被污染的緣由,雖然dup2(file1,file2)與close(file2); fcntl(file1, F_DUPFD, file2)等價,但第一個函數不會致使數據被污染,咱們應該使用第一個函數。

 

5.3 文件更新

  在操做系統中,向文件中寫入數據每每只是暫時寫入至操做系統緩存中,由操做系統控制磁盤中文 件的更新時間。使用sync、fsync、fdatasync函數能夠實現磁盤中文件的實時更新。

  使用sync函數時,文件表中的全部文件將被更新。

  fsync函數只更新制定文件。

  fdatasync函數只更新指定文件中的數據內容,而不更新相應的文件屬性。

 

  若是file status flags中O_SYNC標誌被設置,程序中每次對該文件的write操做都將致使文件被更新;若是O_DSYNC被設置,程序中每次對該文件的write操做都將致使文件中的數據部分被更新。

 5.4 fcntl

  fcntl函數能夠修改已打開文件的屬性。

  當使用fcntl函數獲取文件狀態標記(file status flags)時,因爲O_RDONLY、O_WRONLY、O_RDWR標記具備排外型,沒法被直接識別,須要由O_ACCMODE掩碼轉換後才能夠被識 別。

  示例代碼以下:

#include <fcntl.h>
int
main(int argc, char *argv[])
{
int val;
if (argc != 2)
    err_quit("usage: a.out <descriptor#>");
if ((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0)
    err_sys("fcntl error for fd %d", atoi(argv[1]));
switch (val & O_ACCMODE) {
    case O_RDONLY:
    printf("read only");
    break;
case O_WRONLY:
    printf("write only");
    break;
case O_RDWR:
    printf("read write");
    break;
default:
    err_dump("unknown access mode");
}
if (val & O_APPEND)
    printf(", append");
if (val & O_NONBLOCK)
    printf(", nonblocking");
#if defined(O_SYNC)
if (val & O_SYNC)
    printf(", synchronous writes");
#endif
#if !defined(_POSIX_C_SOURCE) && defined(O_FSYNC)
if (val & O_FSYNC)
printf(", synchronous writes");
#endif
putchar('\n');
exit(0);
}
相關文章
相關標籤/搜索