1. 程式人生 > >檔案 I/O操作open、lseek、read、write、close詳解

檔案 I/O操作open、lseek、read、write、close詳解

一,檔案描述符、套接字和管道

        對於核心而言,所有開啟的開啟的檔案都通過檔案描述符引用。檔案描述符是一個非負整數。

        核心為每個程序維護一個結構體struct task_struct,可稱為程序控制塊(PCB: Process Control Block)或程序描述符,含有一個稱為開啟檔案描述符表的子結構體。普通的檔案、套接字和管道都被放入其中,這說明這三者都被抽象為檔案,共同佔用程序佔用的開啟檔案描述符。

        其中UNIX系統shell使用:

        檔案描述符0與程序的標準輸入相關聯;

        檔案描述符1標準輸出相關聯;

        檔案描述符2

標準出錯輸出相關聯。

二,檔案I/O函式

    1,open 函式可以開啟或建立一個檔案。

#include <fcntl.h>

int open(const char *pathname, int oflag, ... /* mode_t mode */ );

返回值:成功則返回檔案描述符,出錯則返回-1。

引數:

    pathname:是要開啟或建立檔案的名字。

    oflag:說明此函式的多個選項。可將它的選項進行“或”運算構成oflag。

            O_RDONLY            只讀開啟。

            O_WRONLY            只寫開啟。

            O_RDWR                讀、寫開啟。

            這三個選項只能制定且必須一個。下列常量可選:

            O_APPEND            每次都從檔案尾端寫。

            O_CREAT               若檔案不存在,則建立它。使用次選項必須帶第三個引數。

            O_EXECL                如果指定了O_EXECL,而檔案存在,則會出錯。可以用它測試一個檔案是否存在,如果不存在,則建立它。

            O_TRUNC                如果此檔案存在,而且為只寫或只讀開啟,則將其長度截短為0。

    2,create函式建立一個檔案

#include <fcntl.h>

int create(const char *pathname, mode_t mode);

    返回值:成功則返回開啟的檔案描述符,出錯則返回-1。

    由於它只能以只寫的方式開啟所建立的檔案,所以等效於:

open(pathname, 0_WRONLY | O_CREAT | O_TRUNC, mode);

    3,close函式關閉一個開啟的檔案

#include <unistd.h>

int close(int filedes)

    返回值:成功則返回開啟的檔案描述符,出錯則返回-1。

    如果一個程序沒有呼叫close顯示關閉,當程序終止時,核心會自動關閉它所有開啟的檔案。

    4,lseek函式 為一個開啟的檔案設定偏移量

     每個開啟的檔案都有一個與其關聯的“當前檔案偏移量”,它是一個非負整數,用以度量從檔案開始處計算的位元組數。預設情況下,開啟一個檔案,該偏移量被設定為0,除非制定了O_APPEND選項。

#include <unistd.h>

off_t lseek(int filedes, off_t offset, int whence)

    返回值:成功則返回新的檔案的偏移量,出錯則返回-1。

    引數:設定的偏移量offset與whence有關。

        whence     檔案的偏移量設定為offset值
SEEK_SET檔案開始處offset個位元組必須為正數
SEEK_CUR檔案偏移量當前值加offset可正可負
SEEK_END檔案長度加offset可正可負

    如何確定當前開啟檔案的偏移量:

int curpose;
curpose = lseek(filedes, 0, SEEK_CUR);

    也可以用來判斷所涉及的檔案是否可以設定偏移量。因為檔案描述符引用的是一個管道、FIFO或網路套接字,則lseek返回-1,並將error設定為ESPIPE。

    注意:lseek(file, 163840, SEEK_SET);如果檔案偏移量大於檔案的當前長度,對該檔案的下一次寫將加長該檔案,並在檔案中構成一個空洞,這些空洞不在磁碟上佔用儲存區,位於檔案中但沒有寫過的位元組都被讀為0(即空洞都被讀為0)。

    5,read函式 從開啟的檔案讀資料

#include <unistd.h>

ssize_t read(int filedes, void *buf, size_t nbytes);

    返回值:

  • 若成功返回讀到的位元組數;
  • 若已到檔案結尾返回0;
  • 若出錯返回-1。        

    實際讀到的位元組數有可能少於要求讀的位元組數 nbytes:

  • 讀取普通檔案時,在讀到要求位元組數時已到達檔案末尾。例如,若在到達檔案末尾之前還有30個位元組,而要求讀100個位元組,則read返回30,下一次再呼叫read時,它將返回0(檔案尾端)。
  • 當從終端裝置讀時,通常一次最多讀一行。
  • 當從網路讀時,網路中的緩衝機構可能造成返回值小於所要求讀的位元組數。
  • 當從管道或FIFO讀時,如管道包含的位元組少於所需的數量,那麼read將只返回實際可用的位元組數。
  • 當某一訊號造成中斷,而已經讀了部分資料量時。

    6,write函式 向開啟的檔案寫入資料

#include <unistd.h>

ssize_t write(int filedes, const void *buf, size_t nbytes);

    返回值:

  • 若成功返回已寫入的位元組數;
  • 如出錯返回-1。

    返回值通常與引數nbytes的值相同,否則表示出錯(比如緩衝區已滿)。