2012-02-10 72 views
0

我正在使用io.h中的write(fd,buffer,count)將緩衝區寫入文件描述符。如何將寫入緩衝區添加到在io.h中定義的寫入中

現在我發現了巨大的性能問題,因爲每次我調用「寫入」時它都會執行IO操作。

我想在實際將內容寫入文件之前添加緩衝區。

這樣做的最好方法是什麼?

我搜索,發現這個:

http://www.java2s.com/Tutorial/Cpp/0240__File-Stream/filedescriptoroutbuffer.htm

我應該用這種方法,融入我的代碼?這是我應該採取的一個好方法嗎?

但在其中,我看不出如何定義緩衝區大小。

以下是最終代碼:

class fdoutbuf : public std::streambuf { 
    protected: 
     enum { size = 4096 }; 
     int fd; // file descriptor 
     char buf_[size]; 
    public: 
    // constructor 
    fdoutbuf (int _fd) : fd(_fd) { 
     setp(this->buf_, this->buf_ + size - 1); 
    } 
    protected: 
    // write one character 
    virtual int overflow (int c){ 
     if (c != EOF) { 
      char z = c; 
      *this->pptr() = z; 
      this->pbump(1); 
     } 
     return this->sync() == -1? EOF: c; 
    } 
    virtual int sync(){ 
     if (this->pbase() == this->pptr()) { 
      return 0; 
     } 
     int count(this->pptr() - this->pbase()); 
     int rc = write(fd, this->buf_, count); 
     this->setp(this->buf_, this->buf_ + size - 1); 
     return count == rc? 0: -1; 
    } 
}; 


class fdostream : public std::ostream { 
    protected: 
    fdoutbuf buf; 
    public: 
    fdostream (int fd) : std::ostream(0), buf(fd) { 
     rdbuf(&buf); 
    } 
}; 

回答

3

創建緩衝基礎設施並不是真正的火箭科學,但也不是微不足道的。就個人而言,我只是創建一個派生自std::streambuf的類,並使用流緩衝區抽象或流(可能我會使用後者並接受大多數實現引入的小性能影響)。這項工作需要做,這是相當簡單的(這是爲只寫):

struct fdbuf: std::streambuf { 
    enum { size = 4096 }; 
    fdbuf(int fd): fd_(fd) { this->setp(this->buf_, this->buf_ + size - 1); } 
    int overflow(int c) { 
     if (!traits_type::eq_int_type(c, traits_type::eof())) { 
      *this->pptr() = traits_type::to_char_type(c); 
      this->pbump(1); 
     } 
     return this->sync() == -1? traits_type::eof(): traits_type::not_eof(c); 
    } 
    int sync() { 
     if (this->pbase() == this->pptr()) { 
      return 0; 
     } 
     int count(this->pptr() - this->pbase()); 
     int rc = write(this->fd_, this->buf_, count); 
     this->setp(this->buf_, this->buf_ + size - 1); 
     return count == rc? 0: -1; 
    } 
    int fd_; 
    char buf_[size]; 
}; 

現在看來,這可能是值得向大家解釋什麼上面流緩衝區實際上沒有(下面給出了長時間的討論)。所以,這是一個故障:

  • 該代碼使用固定大小的緩衝區。這只是爲了減小示例的大小:它可以容易地擴展爲使用分配的可變大小緩衝區,例如,使用std::vector<char>:大小將成爲默認參數。
  • setp()建立通過流緩存使用的緩衝區,由三個指針的功能:
    • pbase()是緩衝區的開始,即第一個參數setp()
    • epptr()是緩衝區的末尾,即setp()的第二個參數
    • pptr()被設置爲與pbase()相同的值,但是實際上被移動以指示下一個字符的位置的指針。如果這是epptr()當一個字符被寫入時overflow()被調用。
  • 虛擬函數overflow()可能被賦予導致緩衝區溢出的字符。除非用戶代碼使用參數eof()調用它,否則標準庫調用函數時會出現這種情況。爲了處理這個額外的字符,緩衝區被賦予少一個元素,有可用空間:在實際寫入緩衝區之前,可以將字符附加到緩衝區。
  • std::streambuf繼承的traits_type定義了一些函數來確定字符的屬性。在檢查傳遞給overflow()的參數時,將使用函數eq_int_type(),該函數將該流的整數類型的對象與相等進行比較。它將overflow()的參數與表示無效字符的值進行比較,該值是使用eof()獲得的。所有特徵類型的成員是statictypedef,即不需要使用這種類型的對象。當使用std::basic_streambuf的不同模板實例時,使用traits_type非常重要。
  • 雖然緩衝器通常pbase()epptr()到與這兩個端部之間pptr()pptr()可以超出epptr()使用pbump(n)移動:該函數只是增加npptr()。在調用sync()之前,這用於將正確的字符放入緩衝區,然後寫入緩衝區的內容並將其復位。
  • 如果函數失敗,overflow()的返回值爲eof()。在成功執行時,該函數返回與eof()不同的東西,並且通常使用作爲參數傳遞的字符。因爲參數可能是eof(),但僅僅返回參數還不夠好:如果它是eof(),則需要將此值轉換爲not_eof()所做的其他有用值:除非參數爲eof(),否則它將返回參數在這種情況下,它會返回一些合適的其他值。
  • 虛擬函數sync()負責刷新緩衝區。在這種情況下,首先檢查是否有要完成的事情,如果是,則寫入緩衝區的內容。這個函數並沒有任何技巧,但我猜如果write()失敗,我會更加小心,即返回的字符少於緩衝區中的字符。這個版本只是假裝它可以釋放無法寫入的字符,儘管它會顯示錯誤。
  • 該函數仍然使用相同的方法在緩衝區末尾留下一個字符空間來重置緩衝區。
  • 失敗時函數返回-1,成功時返回0。沒有竅門。
+0

這對我來說有點高級。你可以看看這個鏈接:http://www.java2s.com/Tutorial/Cpp/0240__File-Stream/filedescriptoroutbuffer.htm。你們都使用streambuf,但實現是不同的。我可以使用鏈接中的那個嗎?但另一個問題是,鏈接無法控制buf的大小。 – performanceuser 2012-02-10 22:14:54

+0

其實,鏈接指向我的另一個版本的代碼! ;)當我翻譯他的德語書時,我原本是爲尼科的書寫的。除了錯誤(上面的代碼沒有經過測試),這大致是相同的,但沒有緩衝區,上面的版本也使用了一些簡潔的技巧。您可以在任一版本中分配合適的緩衝區(具有適當大小的「std :: vector ')。尼科的書解釋了怎麼回事:也許你應該看看那裏。 – 2012-02-10 23:05:00

+0

真是巧合。那麼你能告訴我如何將緩衝區添加到鏈接中的代碼?它看起來對我更可讀。 – performanceuser 2012-02-11 01:03:14

0

如果您在C++編寫,你可以嘗試使用STL<fstream>輸出到文件中。它已經建立在緩衝區中,並且沒有速度問題。

+0

但我需要使用文件描述符。基礎設施一直在那裏 – performanceuser 2012-02-10 22:16:28