国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

apache中的文件與目錄(2)

2019-11-17 04:50:18
字體:
來源:轉載
供稿:網友
4.4 打開文件
文件打開應該是使用的最多的文件操作了,任何文件在使用之前都必須首先打開。ANSI C標準庫和Unix系統庫函數都提供對“打開文件”這個操作語義的支持。他們提供的接口很相似,參數一般都為“文件名+打開標志位+權限標志位”,Apache中提供了aPR_file_open函數來支持文件打開操作,該函數只是在原有的標準庫的基礎上進行了少許的封裝。apr_file_open無法忽略習慣的巨大力量,它提供了與ANSI C以及Unix系統庫函數類似的接口如下:
 APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new,
                                        const char *fname,
                                        apr_int32_t flag,
                                        apr_fileperms_t perm,
                                        apr_pool_t *pool);
其中fname、flag和perm三個參數與普通的open函數相同,fname分別表示打開的文件的路徑名稱,可以是相對路徑,也可以是絕對路徑。每個封裝都有自定義的一些標志宏,這里也不例外,flag和perm參數都需要用戶傳入APR自定義的一些宏組合,不過由于這些宏的可讀性都很好,不會成為你使用過程的絆腳石。flag是打開文件的標志,包括可讀可寫,Apache中打開標志可以概括為下面的幾種:
打開標志
含義
APR_READ
打開文件為只讀
0x00001
APR_WRITE
打開文件為只寫
0x00002
APR_CREATE
假如文件不存在,創建一個新的文件
0x00004
APR_APPEND
答應將內容追加到文件的末尾,而不是重新覆蓋
0x00008

APR_TRUNCATE
假如文件存在,將其長度設置為0
0x00010
APR_BINARY
打開的不是文本文件,而是二進制文件,在UNIX上,該標志將被忽略
0x00020
APR_BUFFERED
緩存數據,默認情況下不進行數據緩存
0x00040
APR_EXCL
return error if APR_CREATE and file exists
0x00080
APR_DELONCLOSE
關閉后刪除該文件
0x00100
APR_XTHREAD
該標志依靠于具體的平臺,用以確保文件在跨線程訪問中的安全
0x00200
APR_SHARELOCK
平臺依靠標記,用以支持上層的讀寫所訪問從而支持跨進程或者跨機器訪問
0x00400
APR_FILE_NOCLEANUP
通知系統不要在內池中注冊文件清除函數,因此當內存池被銷毀的時候,apr_file_t中的apr_os_file_t句柄將不會被銷毀
0x00800
APR_SENDFILE_ENABLED 
Open with appropriate platform semantics
 for sendfile Operations. Advisory only,           apr_socket_sendfile does not check this flag.
0x01000
perm則是用以記錄文件的存取權限,通常情況下是一個整數,比如0x777,0x666等等。Apache中支持的權限如表4-3所示。
文件的讀取結果由指針apr_file_t返回。整個open過程可以分為四部分:
1)、“打開標志位”轉換;
如前所述,APR定義了自己的“文件打開標志位”,所以在apr_file_open的開始需要將這些專有的“文件打開標志位”轉換為Unix平臺通用的“文件打開標志位”,對應的轉換表如下:

Apache打開標志
UNIX庫函數內部標志
APR_READ&&APR_WRITE
O_RDWR
APR_READ
O_RDONLY
APR_WRITE
O_WRONLY
APR_CREATE
O_CREAT
O_CREAT&&APR_EXCL
O_CREAT&O_EXCL
APR_EXCL&&!APR_CREATE
答應組成員讀取
APR_APPEND
O_APPEND
APR_TRUNCATE
O_TRUNC
O_BINARY
O_BINARY
APR_BUFFERED&&APR_XTHREAD
答應其余成員讀取
2)、權限標志位”轉換;
同1)理,專有的APR“權限標志位”需要轉換為Unix平臺通用的“權限標志位”;轉換使用函數apr_unix_perms2mode實現,轉換根據表4-2的對應關系實現。函數返回的權限最終傳遞給open函數的標志位。
(3)、調用Unix的本地API打開文件;
(4)、設置apr_file_t變量相關屬性值;
APR 文件I/O封裝支持非阻塞I/O帶超時等待以及緩沖I/O,默認情況下為阻塞的,即BLK_ON。
APR文件的另外一個非凡之處就是支持緩沖特性。由于磁盤讀取的速度瓶頸,使得頻繁的從磁盤讀取文件在一定程度上會影響執行效率,因此為了提高讀取效率,APR支持文件的緩存讀寫,即開辟一塊大的緩沖內存區,用以保存實際從磁盤中讀取得數據,這樣用戶每次就不需要讀寫磁盤,而只要讀寫內存,通過這種緩沖策略,可以改善一定的性能。是否緩沖可通過“文件打開標志位APR_BUFFERED”設置。一旦設置為緩沖讀寫,則apr_file_open會在pool中開辟大小為APR_FILE_BUFSIZE(4096)的緩沖區供使用。
創建函數中一個比較重要的就是內存池中apr_file_t類型的清除函數注冊。當內存池被銷毀的時候,對于所有的apr_file_t類型將調用apr_unix_file_cleanup函數進行清除。與創建類似,清除也包括四方面的工作:
(1)、
(2)、關閉文件描述符filedes,假如文件的打開標志是APR_DELONCLOSE,那么在關閉之后還得將該文件刪除;假如文件可能跨進程使用,那么還得銷毀互斥鎖。
(3)、
 
4.5 文件讀取

4.5.1普通文件讀取
文件的讀寫操作定義在readwrite.c中。函數的原型與標準的接口非常類似:
APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf, apr_size_t *nbytes)
thefile是需要讀取的文件的描述結構,而buf是文件讀取保存的緩沖區。nbytes則是從文件中需要讀取的字節數。Apache中的文件讀取在內部分為兩種機制:支持讀寫緩存的和不支持讀寫緩存的,讀寫是否需要支持緩存,有apr_file_t內部的buffered成員決定,buffered=1表示內部必須支持緩存,否則不需要使用緩存。
我們首先分析最普通的內部不使用緩存的讀寫情況,下面是讀取的核心代碼:
{
    apr_ssize_t rv;
    apr_size_t bytes_read;
 
    if (*nbytes <= 0) {
        *nbytes = 0;
        return APR_SUCCESS;
    }
 
    {
        bytes_read = 0;
        if (thefile->ungetchar != -1) {
            bytes_read = 1;
            *(char *)buf = (char)thefile->ungetchar;
            buf = (char *)buf + 1;
            (*nbytes)--;
            thefile->ungetchar = -1;
            if (*nbytes == 0) {
                *nbytes = bytes_read;
                return APR_SUCCESS;
            }
        }
 
        do {
            rv = read(thefile->filedes, buf, *nbytes);      u
        } while (rv == -1 && errno == EINTR);
#ifdef USE_WAIT_FOR_IO
        if (rv == -1 &&
            (errno == EAGAIN errno == EWOULDBLOCK) &&
            thefile->timeout != 0) {
            apr_status_t arv = apr_wait_for_io_or_timeout(thefile, NULL, 1);
            if (arv != APR_SUCCESS) {               v

                *nbytes = bytes_read;
                return arv;
            }
            else {
                do {
                    rv = read(thefile->filedes, buf, *nbytes);
                } while (rv == -1 && errno == EINTR);
            }
        } 
#endif
        *nbytes = bytes_read;
        if (rv == 0) {
            thefile->eof_hit = TRUE;                   w
            return APR_EOF;
        }
 
        if (rv > 0) {
            *nbytes += rv;                              x
            return APR_SUCCESS;
        }
        return errno;
    }
}
讀取的主要操作就是調用標準的文件讀操作read,文件中讀取的數據直接保存到輸出緩沖區buf中,確實沒有進行任何的內部緩存。
第一次讀取結束后,函數將根據讀取的返回值做進一步的處理:
返回EINTR,見代碼u
返回EINTR意味著讀取操作被中斷信號無意打斷,而不是讀取操作本身出現任何問題,因此此時必須無條件重新啟動讀操作,這就是將讀操作放在循環中的原因之一,代碼見。
返回EAGAIN或者EWOULDBLOCK,見代碼v
讀操作發生失敗的另外一個可能性就是文件暫時不可用,因此此時應該稍等片刻再嘗試,這種情況通常會返回EAGAIN錯誤碼,對于GNU C庫而言,EWOULDBLOCK與EAGAIN的含義完全相同,只是換了一個名字而已,不過對于早期的版本可能存在差異。因此穩妥的做法就是同時檢測EAGAIN和EWOULDBLOCK錯誤碼。
一般下面的兩種情況可能返回這兩個錯誤碼:
(1)、對非阻塞模式的對象進行某個會阻塞的操作可能會返回該錯誤碼,再次做同樣的操作就會阻塞直到某種條件使它可以讀寫。
(2)、某個資源上的故障使操作不能進行。例如fork有可能返回著個錯誤,這也表示這個故障可以被克服,所以你的程序可以以后嘗試這個操作。停幾秒讓其他進程釋放資源然后再試也許是個好主意。這種故障可能很嚴重并會影響整個系統,所以通常交互式的程序會報告用戶這個錯誤并返回命令循環。

假如apr_file_t結構中設置了超時時間timeout,同時發現必須重新讀取(返回碼為EAGAIN或者EWOULDBLOCK),那么Apache將調用apr_wait_for_io_or_timeout函數等待重新讀取文件。apr_wait_for_io_or_timeout函數內部使用了I/O的多路復用技術poll,具體的細節我們在網絡I/O章節描述。假如在給定的超時時間內,文件還是不答應進行讀取操作,那么此時函數將直接返回,否則函數將重新調用下面的語句:
do {
    rv = read(thefile->filedes, buf, *nbytes);
} while (rv == -1 && errno == EINTR);
由于此時文件的狀態處于肯定答應進行操作狀態,因此不再需要進行額外的異常處理,唯一的就是防止被信號無意打斷。
到達文件末尾(rv==0),見代碼w
假如read函數返回0,此時意味著已經讀取到整個文件,此時設置文件的eof_hit=1,至此整個文件讀取結束。
讀取非空字節(rv>0),見代碼x
此時累計讀取的總字節數目。
上面的幾個文件讀取的處理步驟是大多數文件讀取的標準的讀取操作,因此非常的好理解。
事實上,對于文件讀取分析的重點并不是上面的普通的讀取,而是使用緩存的讀取。一般情況下I/O操作是相當耗費時間的,因此僅僅一次從文件中直接讀取數據保存到緩沖區中所花的時間可能答應忽略不計,但是假如文件讀取操作非常的頻繁的話,那么這將無疑是一個不小的時間耗費,甚至可能是性能瓶頸。因此為了有效地提高讀寫性能,Apache提供了緩存讀取的策略。所謂緩存讀取,就是先把文件中的數據讀取到一個緩存中,然后以后再次需要讀取數據的時候,不再從文件本身去讀取,而是從緩存中去讀取。通過這種策略使文件I/O讀取變成內存讀取,從而提高了讀取速度。而寫入時候也是類似,先寫入到緩存中,然后在一次寫入磁盤中,從而將多次磁盤寫入變為多次內存寫入。apr_file_t結構中的buffer結構的作用正是這個目的。緩存讀取的策略可以用下面的示意圖描述:
apache中的文件與目錄(2)(圖一)
使用了緩沖區后,文件操作者將通過緩沖區與磁盤文件打交道。整個緩沖區的實現機制,我們給出下面的一個更具體的圖片,通過圖示,我們可以理解apr_file_t中一些很晦澀的成員變量,事實上這些成員變量僅僅是配合緩沖區機制而使用的,而且僅僅使用緩沖區的時候才起作用。
apache中的文件與目錄(2)(圖二)
上面的圖示被我們分為了三個層次:最底層的是進行文件讀寫的用戶,它擁有自定義的緩沖區,我們稱之為用戶緩沖區;中間的是apr_file_t結構內的緩沖區,它用以保存讀寫緩存數據。事實上用戶總是跟這個層次的緩沖區打交道;最上層的則是磁盤文件。在各個層次中我們用”////////”表示模擬當前的緩沖區大小。
從圖示中我們可以看到至少存在四種緩沖區長度:
1)、磁盤文件的實際長度。當使用read在文件中讀寫的時候,文件內部會維護一個內部指針指示當前的讀取位置,apr_file_t結構中使用filePtr模擬該內部指針,因此filePtr總是指向實際文件內部的當前讀取位置。
2)、文件緩沖區中現有數據的長度,它的大小由apr_file_t結構內的dataRead指示。通常情況下,dataRead的大小與filePtr指向的位置偏移相等。
3)、最終用戶在文件緩沖區中讀取的數據的當前指針,由apr_file_t結構內的bufpos指針指示。
4)、用戶緩沖區的長度,其最新讀寫位置由pos指示。
基于緩沖區,整個讀取操作的流程發生了根本的變化。任何讀取首先嘗試從文件緩沖區中讀取,假如請求讀取的長度在文件緩沖區的長度范圍之內,那么直接返回數據。假如需要讀取的內容超出了文件緩沖區的范圍,那么我們還必須再去實際的磁盤文件中去讀取,并返回,同時更新緩存區中的數據。
    if (thefile->buffered) {
        char *pos = (char *)buf;
        apr_uint64_t blocksize;
        apr_uint64_t size = *nbytes;
 
#if APR_HAS_THREADS
        if (thefile->thlock) {
            apr_thread_mutex_lock(thefile->thlock);

        }
#endif
假如支持多線程的操作,那么在對文件進行操作之前必須互斥量鎖定,確保操作的安全性。同樣在讀取結束后還必須是unlock該互斥變量。
        if (thefile->direction == 1) {
            apr_file_flush(thefile);
            thefile->bufpos = 0;
            thefile->direction = 0;
            thefile->dataRead = 0;
        }
 
        rv = 0;
        if (thefile->ungetchar != -1) {
            *pos = (char)thefile->ungetchar;
            ++pos;
            --size;
            thefile->ungetchar = -1;
        }
        while (rv == 0 && size > 0) {
            if (thefile->bufpos >= thefile->dataRead) {
                int bytesread = read(thefile->filedes, thefile->buffer, APR_FILE_BUFSIZE);
                if (bytesread == 0) {
                    thefile->eof_hit = TRUE;
                    rv = APR_EOF;
                    break;
                }

                else if (bytesread == -1) {
                    rv = errno;
                    break;
                }
                thefile->dataRead = bytesread;
                thefile->filePtr += thefile->dataRead;
                thefile->bufpos = 0;
            }
 
            blocksize = size > thefile->dataRead - thefile->bufpos ? thefile->dataRead - thefile->bufpos : size;
            memcpy(pos, thefile->buffer + thefile->bufpos, blocksize);
            thefile->bufpos += blocksize;
            pos += blocksize;
            size -= blocksize;
        }
while循環讀取的核心代碼就位于while循環中。dataRead是實際讀取到緩沖區中的數據的長度,當然它肯定小于或者等于實際的文件的總長度。bufpos則是用戶讀取的緩沖區中的實際字節數目,當然bufpos肯定也是小于或者等于dataRead的。它們的關系如上圖所示。用戶假如從緩沖區中讀取數據的話它最多只能讀取到dataRead字節的長度。當用戶從緩沖區中讀取數據的時候,緩沖區的內部的指針變量bufpos不斷往后移動。
函數將根據bufpos的位置做不同的策略:
(1)、起始的時候,bufpos=0,緩沖區中的數據為dataRead,用戶請求的數據為size大小。此時將開始嘗試讀取緩沖區中的數據。假如請求的字節小于緩沖區的dataRead長度,那么直接將緩沖區中size大小的數據拷貝到輸出緩沖區pos中。這種情況是最簡單的一種。
由于filepos為0,這時候執行的代碼將演變為如下:
            blocksize = size;//size > thefile->dataRead -0 ? thefile->dataRead: size;
            memcpy(pos, thefile->buffer + 0, blocksize);
            thefile->bufpos += blocksize;

            pos += size;
            size -= size;
(2)、當bufpos=0,即開始讀取的時候,假如用戶請求的數據長度超出了dataRead的長度,那么此時用戶第一次讀取只能讀取到dataRead的數據,還剩余size-dataRead需要從文件中讀取。因此,第一次的讀取演變為如下的代碼:
            blocksize = thefile->dataRead;//size > thefile->dataRead - 0 ? thefile->dataRead - 0 : size;
            memcpy(pos, thefile->buffer + 0, blocksize);
            thefile->bufpos += blocksize;
            pos += thefile->dataRead;
            size -= thefile->dataRead;
此時各個指針的位置如下圖所示意
apache中的文件與目錄(2)(圖三)
從上圖可以看到,第一次讀取之后,各個指針都指向相應的緩沖區的末尾,pos指向用戶緩沖區,隨后的數據直接從pos位置往后拷貝;bufpos指向文件緩沖區的末尾。由于此時尚有size-dataRead大小的數據尚未讀取,因此,函數將從thefile->filedes中去讀取:
            if (thefile->bufpos >= thefile->dataRead) {
                int bytesread = read(thefile->filedes, thefile->buffer, APR_FILE_BUFSIZE);
                if (bytesread == 0) {
                    thefile->eof_hit = TRUE;
                    rv = APR_EOF;
                    break;
                }
                else if (bytesread == -1) {
                    rv = errno;

                    break;
                }
                thefile->dataRead = bytesread;
                thefile->filePtr += thefile->dataRead;
                thefile->bufpos = 0;
            }
但實際上,當Apache再次到磁盤文件中去讀取的時候,它并不會吝嗇的僅讀取size-dataRead大小,相反它會調用read函數一次性的從文件中讀取APR_FILE_BUFSIZE(4K)大小的數據到文件緩沖區中,然后設置dataRead為新的實際的讀取字節長度。
        *nbytes = pos - (char *)buf;
        if (*nbytes) {
            rv = 0;
        }
#if APR_HAS_THREADS
        if (thefile->thlock) {
            apr_thread_mutex_unlock(thefile->thlock);
        }
#endif
        return rv;
    }
 
在apr_file_read函數的基礎之上,APR提供了額外的幾個輔助函數:
■ APR_DECLARE(apr_status_t) apr_file_getc(char *ch, apr_file_t *thefile);
用以從文件中獲取一個字符
■ APR_DECLARE(apr_status_t) apr_file_read_full(apr_file_t *thefile, void *buf,
                                             apr_size_t nbytes,
                                             apr_size_t *bytes_read)

apr_file_read函數通常用于讀取指定字節的數據,并且永遠不會超過這個指定值,但是實際的讀取字節數則可以少于這個值。
而apr_file_read_full與apr_file_read非常類似,主要的區別就是,對于指定的字節數nbytes,函數必須全部讀取完畢才肯罷休,任何時候假如發現讀取得字節數小于nbytes,函數都將繼續等待。這種讀取方式我們稱之為“全字節讀取方式”。
4.5.2字符串讀取
 
4.5.3文件寫入
文件寫入通過函數apr_file_write實現,與標準的寫入函數相同,它也具有三個參數:
APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes)
thefile是寫入的文件描述符,buf是寫入的源目標字符串,nbytes是需要寫入的字節總數目。
與讀取類似,寫入也分為緩沖寫入和非緩沖寫入兩種。對于非緩沖寫入,所有的數據是直接寫入到文件中,而對于緩沖寫入,所有的數據先寫入到文件緩沖區中,然后再從緩沖區中寫入到文件中。
對于非緩沖寫入的核心代碼如下所示:
        apr_size_t rv;
 
        do {
            rv = write(thefile->filedes, buf, *nbytes);
        } while (rv == (apr_size_t)-1 && errno == EINTR);
#ifdef USE_WAIT_FOR_IO
        if (rv == (apr_size_t)-1 &&
            (errno == EAGAIN errno == EWOULDBLOCK) &&
            thefile->timeout != 0) {
            apr_status_t arv = apr_wait_for_io_or_timeout(thefile, NULL, 0);
            if (arv != APR_SUCCESS) {
                *nbytes = 0;
                return arv;
            }
            else {
                do {
                    do {
                        rv = write(thefile->filedes, buf, *nbytes);
                    } while (rv == (apr_size_t)-1 && errno == EINTR);
                    if (rv == (apr_size_t)-1 &&
                        (errno == EAGAIN errno == EWOULDBLOCK)) {

                        *nbytes /= 2;
                    }
                    else {
                        break;
                    }
                } while (1);
            }
        } 
#endif
        if (rv == (apr_size_t)-1) {
            (*nbytes) = 0;
           return errno;
        }
        *nbytes = rv;
        return APR_SUCCESS;
 
對于緩沖寫入,其實現代碼如下所示:
    apr_size_t rv;
 
    if (thefile->buffered) {
        char *pos = (char *)buf;
        int blocksize;
        int size = *nbytes;
 
        if ( thefile->direction == 0 ) {
            apr_int64_t offset = thefile->filePtr - thefile->dataRead + thefile->bufpos;
            if (offset != thefile->filePtr)
                lseek(thefile->filedes, offset, SEEK_SET);                  u
            thefile->bufpos = thefile->dataRead = 0;
            thefile->direction = 1;
        }
 
        rv = 0;
        while (rv == 0 && size > 0) {
            if (thefile->bufpos == thefile->bufsize)   /* write buffer is full*/

                rv = apr_file_flush(thefile);                v
 
            blocksize = size > thefile->bufsize - thefile->bufpos ?
                        thefile->bufsize - thefile->bufpos : size;
            memcpy(thefile->buffer + thefile->bufpos, pos, blocksize);                     
            thefile->bufpos += blocksize;                  w
            pos += blocksize;
            size -= blocksize;
        }
 
        return rv;
    }
在分析文件緩沖寫之前,我們先看一下實際的文件系統的讀寫情況。在文件系統內部始終維持一個內部位置指針,該指針隨著當前讀取和寫入的位置的改變而不停的改變,同時任何一次讀取和寫入都是在內部指針指向的位置基礎上進行的,因此假如在寫之前,文件內部的指針偏移為offset,則寫入的數據將插入到offset之后。
這種情況對于APR文件緩沖而言也必須實現同樣的效果。不過,假如文件thefile在寫之前剛被讀過,則存在兩個offset偏移位置:
1)、filePtr。任何時候,實際文件內部的指針用filePtr進行模擬指示,它始終與內部指針保持同步。
2)、bufpos。該位置指示用戶實際已經讀取的緩沖區位置,它在實際文件內部的偏移量為filePtr-(dataRead-bufpos)。
那么在寫入時候,新的數據是插入到filePtr之后還是filePtr-(dataRead-bufpos)之后呢?答案只有一個:一切從用戶的角度出發。對于最終用戶而言,它能夠觀察到的現象是:數據剛被讀取到bufpos位置,至于文件緩沖區的文件長度多少用戶根本無法了解到。因此對于用戶而言,文件的偏移量應該是filePtr-(dataRead-bufpos),而不是filePtr,即使實際的內部文件指針偏移量確實是filePtr。
因此假如filePtr和filePtr-(dataRead-bufpos)不一致的時候,必須調整文件內部的實際偏移指針為filePtr-(dataRead-bufpos),以保證正確的寫入位置。另外必要的工作就是初始化寫入緩沖區,這正是代碼u所實現的任務。
一旦定位完畢,那么就可以進行數據寫入了。用戶緩沖區中所有的數據首先都立即寫入到文件緩沖區中,寫入的時候可能發生的情況包括下面幾種:
1)、緩沖區已滿。apr_file_t中緩沖區的大小由bufsize確定,默認大小為4K。一旦緩沖區已滿,那么緩沖區中的數據將使用apr_file_flush一次性寫入到實際的文件中,同時再次初始化緩沖區。Apr_file_flush函數的實現非常簡單,順便一看:
APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile)
{
    if (thefile->buffered) {
        if (thefile->direction == 1 && thefile->bufpos) {
            apr_ssize_t written;
 
            do {
                written = write(thefile->filedes, thefile->buffer, thefile->bufpos);

            } while (written == -1 && errno == EINTR);
            if (written == -1) {
                return errno;
            }
            thefile->filePtr += written;
            thefile->bufpos = 0;
        }
    }
    return APR_SUCCESS;
}
函數中所作的無非就是不斷調用write寫入。寫入成功后filePtr和緩沖區的開始位置,這兩個步驟都被隱藏在該函數中,因此你在寫入函數中看不到也就不希奇了。
2)、緩沖區的空閑空間足夠寫入,即size <= thefile->bufsize - thefile->bufpos。此時,直接調用memcpy將用戶緩沖區中的數據拷貝到文件緩沖區中,并調整用戶緩沖區pos和文件緩沖區bufpos的位置。
3)、用戶要求寫入的數據空閑空間不夠一次寫入,此時將分為多次寫入。假如寫入過程中空間已滿,使用1)的方法,否則使用2)的方法。
 
在該函數的基礎之上,APR還提供了一些輔助擴充函數:
■ APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile);
用以向文件中寫入一個字符。
■ APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t *thefile)
用以向文件中寫入一個字符串。
■ APR_DECLARE(apr_status_t) apr_file_writev(apr_file_t *thefile, const struct iovec *vec,
                                          apr_size_t nvec, apr_size_t *nbytes)
批量文件寫入。需要批量寫入的數據保存在vec中。假如系統中定義了writev函數,則調用writev函數批量寫入。假如系統不支持writev函數,那么假如要寫入整個iovec數組,可以使用兩種變通策略:
第一種就是逐一遍歷iovec數組中的每一個元素并將其寫入到文件中。這種做法存在一個問題,就是原子性寫入。Writev函數寫入所有數據的時候是保持原子性的。而迭代則明顯無法保持這種特性。
另一種可選策略就是首先將iovec數組中的數據集中寫入到一個緩沖區中,然后再將該緩沖區寫入到文件中。這種策略也是不合理的,因此你根本就不知道一個iovec數組中會包含多少數據,你也就無法確定緩沖區的大小。
為了保持writev的真正語義,最合理的策略就是僅寫入iovec數組中的第一個數據,即vec[0]。Callers of file_writev() must deal with partial writes as they normally would. If you want to ensure an entire iovec is written, use apr_file_writev_full()。
■APR_DECLARE(apr_status_t) apr_file_write_full(apr_file_t *thefile,
                                              const void *buf,
                                              apr_size_t nbytes,

                                              apr_size_t *bytes_written)
與apr_file_read_full類似,該函數使得寫入的字符串必須達到指定的nbytes,任何時候假如寫入的字符數小于nbytes,函數都將等待。這種方式我們稱之為“全字節寫入方式”。
¢ APR_DECLARE(apr_status_t) apr_file_writev_full(apr_file_t *thefile,
                                               const struct iovec *vec,
                                               apr_size_t nvec,
                                               apr_size_t *bytes_written)
apr_file_writev_full是apr_file_writev函數的全字節寫入方式的版本。該函數定義在fullrw.c中。
文件打開、文件讀取以及文件寫入是最普通三種文件操作,也是APR中使用的最多的操作,APR中相當一部分的文件操作函數都是基于這三個函數構建起來的,最典型的就是文件內容拷貝和追加。在接下來的部分我們在分析文件內容拷貝和追加的時候更應該關注的是這三個函數的使用。
關于作者
張中慶,目前主要的研究方向是嵌入式瀏覽器,移動中間件以及大規模服務器設計。目前正在進行Apache的源代碼分析,計劃出版《Apache源代碼全景分析》上下冊。Apache系列文章為本書的草案部分,對Apache感愛好的朋友可以通過flydish1234 at sina.com.cn與之聯系!

假如你覺得本文不錯,請點擊文后的“推薦本文”鏈接?。?/div>


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 青田县| 宣城市| 秦安县| 青阳县| 彰化市| 江北区| 河津市| 盐池县| 舞钢市| 唐山市| 永新县| 江陵县| 自治县| 五大连池市| 民县| 太白县| 兰坪| 静宁县| 汤阴县| 金秀| 平凉市| 兰考县| 民丰县| 蓝山县| 东乌珠穆沁旗| 黑龙江省| 塘沽区| 中牟县| 柳州市| 交城县| 惠东县| 盐池县| 宜川县| 陵川县| 南昌县| 崇仁县| 娄烦县| 陇西县| 肇庆市| 冀州市| 梁平县|