1. 程式人生 > >Linux中文件I/O函數

Linux中文件I/O函數

一個 lose lin one 含義 共享 保持 sendfile 使用

一、lseek函數

每個打開文件都有一個與其相關聯的“當前文件偏移量”。它通常是一個非負整數,用以度量從文件開始處

計算的字節數。通常,讀、寫操作都從當前文件偏移量處開始,並使偏移量增加所讀寫的字節數。當打開一個文

件時,除非指定O_APPEND選項(調用open函數時使用了O_APPEND),否則該偏移量被設置為0。調用lseek函數顯

式地為一個打開文件設置偏移量。該函數原型為:

#include <unistd.h>
off_t lseek(int fd,off_t offset,int whence);

該函數若成功則返回新的文件偏移量,若出錯返回-1。參數fd為打開的文件描述符,參數offset與參數whence


的值有關:

  • 若whence是SEEK_SET,則將該文件的偏移量設置為距文件開始處offset個字節。
  • 若whence是SEEK_CUR,則將該文件的偏移量設置為其當前值加offset,offset可為正為負。
  • 若whence是SEEK_END,則將該文件的偏移量設置為文件長度加offset,offset可正可負。

若lseek成功執行,則返回新的文件偏移量。如果文件描述符指向的是一個管道、FIFO或網絡套接字,則lseek

返回-1,並將errno設置為ESPIPE。

二、dup和dup2函數

dup和dup2系統調用都可以用來復制文件描述符,函數的原型為:

#include <unistd.h>
int
dup(int fd); int dup2(int fd,int fd2);

函數成功執行返回新的文件描述符,若出錯返回-1。由dup返回的新文件描述符一定是當前可用文件描述符中的

最小數值。對於dup2,可以用fd2參數指定新的文件描述符的值。如果fd2已經打開,則先將其關閉。若fd等於fd2,

則dup2返回fd2,而不關閉它。否則,fd2的FD_CLOEXEC文件描述符標誌就被清除,這樣fd2在進程調用exec時是打

開狀態。

dup(fd);等效於fcntl(fd,F_DUPFD,0); dup2(fd,fd2);等效於close(fd2);fcntl(fd,F_DUPFD,fd2);

而dup2並不完全等同於close加上fcntl。它們之間的區別有:

(1)dup2是一個原子操作,而close和fcntl包括了兩個函數調用。有可能在close和fcntl之間調用了信號捕獲

函數,它可能修改文件描述符。如果不同的線程改變了文件描述符的話也會出現同樣的問題。

(2)dup2和fcntl有一些不同的errno。

三、fcntl函數

fcntl系統調用可以用來對已經打開的文件描述符進行各種控制操作以改變已打開文件的各種屬性,該函數的

原型為:

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd,int cmd,.../*int arg*/);

fcntl函數有以下5種功能:

(1)復制一個已有的文件描述符(cmd=F_DUPFD或F_DUPFD_CLOEXEC)。

(2)獲取/設置文件描述符標誌(cmd=F_GETFD或F_SETFD)。

(3)獲取/設置文件狀態標誌(cmd=F_GETFL或F_SETFL)。

(4)獲取/設置異步I/O所有權(cmd=F_GETOWN或F_SETOWN)。

(5)獲取/設置記錄鎖(cmd=F_GETLK、F_SETLK或F_SETLKW)。

F_DUPFD:復制文件描述符fd。新文件描述符作為函數值返回。它是尚未打開的各描述符中大於或等於第3個

參數值(取為整型值)中各值的最小值。新文件描述符與fd共享同一文件表項。但是新的文件描述符有它自己的

一套文件描述符標誌,其FD_CLOEXEC文件描述符標誌被清除(這表示該文件描述符在exec時仍保持有效)。

F_DUPFD_CLOEXEC:復制文件描述符,設置與新的文件描述符關聯的FD_CLOEXEC文件描述符標誌的值,返回

新的文件描述符。

F_GETFD:對應於fd的文件描述符標誌作為函數值返回當前只定義了一個文件描述符標誌FD_CLOEXEC。

F_SETFD:對於fd設置文件描述符標誌。新標誌值按第3個參數(取為整型值)設置。

F_GETFL:對應於fd的文件狀態標誌作為函數值返回。

F_SETFL:將文件狀態標誌設置為第3個參數的值(取為整型值)。可以更改的幾個標誌為:O_APPEND、O_NO

NBLOCK、O_SYNC、O_DSYNC、O_RSYNC、O_FSYNC和O_ASYNC。

F_GETOWN:獲取當前接收SIGIO和SIGURG信號的進程ID或進程組ID。

F_SETOWN:設置接收SIGIO和SIGURG信號的進程ID或進程組ID。正的arg指定一個進程ID,負的arg表示等於

arg絕對值的一個進程組ID。

fcntl的返回值與命令有關。如果出錯,所有命令都返回-1,如果成功則返回某個其它值。F_DUPFD返回新的

文件描述符,F_GETFD和F_GETFL返回相應的標誌,F_GETOWN返回一個正的進程ID或負的進程組ID。

四、ioctl函數

ioctl系統調用通常用來控制設備,不能用其它函數進行的控制操作都可以用ioctl來進行,該函數原型為:

#include <unistd.h>
#include <sys/ioctl.h>
int ioctl(int fd,int request,...);

ioctl用來控制特殊設備文件的屬性,第一個參數fd必須是一個已經打開的文件描述符,第三個參數一般為

char *argp,它隨第二個參數request的不同而不同。參數request決定了參數argp是向ioctl傳遞數據還是從io

ctl獲取數據。

五、readv和writev函數

readv函數將數據從文件描述符讀到分散的內存塊中,即分散讀;writev函數則將多塊分散的內存數據一並

寫入文件描述符中,即集中寫。函數的原型為:

#include <sys/uio.h>
ssize_t readv(int fd,const struct iovec *iov,int count);
ssize_t writev(int fd,const struct iovec *iov,int count);

函數中fd參數是被操作的目標文件描述符。iov參數的類型是iovec結構數組,該結構體描述一塊內存區。參

數count是iov數組的長度,即有多少塊內存數據需要從fd讀出或寫到fd。readv和writev函數在成功時返回讀出/

寫入fd的字節數,失敗則返回-1並設置errno。

六、sendfile函數

sendfile函數在兩個文件描述符之間直接傳遞數據(完全在內核中操作),從而避免了內核緩沖區和用戶緩

沖區之間的數據拷貝,效率很高,被稱為零拷貝。該函數的原型為:

#include <sys/sendfile.h>
ssize_t sendfile(int out_fd,int in_fd,off_t *offset,size_t count);

函數中in_fd參數是待讀出內容的文件描述符,out_fd參數是待寫入內容的文件描述符。offset參數指定從讀

入文件流的哪個位置開始讀,如果為空,則使用讀入文件流默認的起始位置。count參數指定在文件描述符in_fd

和out_fd之間傳輸的字節數。sendfile函數成功時返回傳輸的字節數,失敗則返回-1並設置errno。in_fd必須是一

個支持類似mmap函數的文件描述符,即它必須指向真實的文件,不能是socket和管道;而out_fd則必須是一個soc

ket。因此,sendfile函數幾乎是專門為在網絡上傳輸文件而設計的。

七、mmap和munmap函數

mmap函數用於申請一段內存空間,可以將這段內存空間作為進程間通信的共享內存,也可以將文件直接映射

到其中。munmap函數則釋放由mmap創建的這段內存空間。函數原型為:

#include <sys/mman.h>
void* mmap(void *start,size_t length,int prot,int flags,int fd,off_t offset);
int munmap(void *start,size_t length);

函數中start參數允許用戶使用某個特定的地址作為這段內存的起始地址,如果它被設置成NULL,則系統自動

分配一個地址。length參數指定內存段的長度。prot參數用來設置內存段的訪問權限,它可以取以下幾個值的按位

或:(1)PROT_READ:內存段可讀。(2)PROT_WRITE:內存段可寫。(3)PROT_EXEC:內存段可執行。(4)PRO

T_NONE:內存段不能被訪問。

flags參數控制內存段內容被修改後程序的行為,它可以被設置為某些值的按位或(其中MAP_SHARED和MAP_PRIVATE

是互斥的,不能同時指定)。flags參數的常用值有:MAP_SHARED、MAP_PRIVATE、MAP_ANONYMOUS、MAP_FIXED、MA

P_HUGETLB。fd參數是被映射文件對應的文件描述符,它一般通過open系統調用獲得。offset參數設置從文件的何

處開始映射(對於不需要讀入整個文件的情況)。

mmap函數成功時返回指向目標內存區域的指針,失敗則返回MAP_FAILED((void*)-1)並設置errno。munmap函數

成功時返回0,失敗則返回-1並設置errno。

八、splice函數

splice函數用於在兩個文件描述符之間移動數據,也是零拷貝操作。該函數的原型為:

#include <fcntl.h>
ssize_t splice(int fd_in,loff_t *off_in,int fd_out,loff_t *off_out,size_t len,unsigned int flags);

函數中fd_in參數是待輸入數據的文件描述符,如果fd_in是一個管道文件描述符,那麽off_in參數必須被設置

為NULL,如果fd_in不是一個管道文件描述符,那麽off_in表示從輸入數據流的何處開始讀取數據,此時若off_in

被設置為NULL,則表示從輸入數據流的當前偏移位置讀入;若off_in不為NULL,則它將指出具體的偏移位置。fd_o

ut/off_out參數的含義與fd_in/off_in相同,不過用於輸出數據流。len參數指定移動數據的長度;flags參數則控

制數據如何移動,它可以被設置為某些值的按位或,常用值為:SPLICE_F_MOVE、SPLICE_F_NONBLOCK、SPLICE_F_

MORE、SPLICE_F_GIFT。使用splice函數時,fd_in和fd_out必須至少有一個是管道文件描述符。splice函數調用成

功時返回移動字節的數量,它可能返回0,表示沒有數據需要移動,這發生在從管道中讀取數據(fd_in是管道文件

描述符)而該管道沒有被寫入任何數據時。splice函數失敗時返回-1並設置errno。

九、tee函數

tee函數在兩個管道文件描述符之間復制數據,也是零拷貝操作。它不消耗數據,因此源文件描述符上的數據仍

然可以用於後續的讀操作。該函數原型為:

#include <fcntl.h>
ssize_t tee(int fd_in,int fd_out,size_t len,unsigned int flags);

該函數的參數的含義與splice相同(但fd_in和fd_out必須都是管道文件描述符)。tee函數成功時返回在兩個文

件描述符之間復制的數據數量(字節數)。返回0表示沒有復制任何數據。tee失敗時返回-1並設置errno。

Linux中文件I/O函數