如何将写缓冲区添加到io.h中定义的write中

时间:2012-02-10 21:06:07

标签: c++ buffer

我在io.h中使用write(fd,buffer,count)将缓冲区写入文件描述符。

现在我发现了巨大的性能问题,因为每次我调用“write”它都会执行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);
    }
};

2 个答案:

答案 0 :(得分: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()可能被赋予导致缓冲区溢出的字符。除非用户代码调用参数traits_type,否则标准库调用函数时就是这种情况。为了处理这个额外的字符,缓冲区被赋予一个元素,减去可用空间:在实际写入缓冲区之前,可以将字符附加到缓冲区。
  • std::streambuf继承的overflow()定义了许多用于确定字符属性的函数。检查传递给eq_int_type()的参数时,使用函数overflow(),该函数与流的整数类型的对象进行比较以获得相等性。它将eof()的参数与表示使用static获得的无效字符的值进行比较。特征类型的所有成员都是typedeftraits_type s,即不需要使用此类型的对象。使用std::basic_streambuf
  • 的不同模板实例时,pbase()的使用非常重要
  • 虽然缓冲区通常epptr()pptr()pptr()之间有epptr(),但pbump(n)可以使用n移出pptr() :此功能只会将sync()添加到overflow()。这用于在调用eof()之前将当前字符放入缓冲区,这只是写入缓冲区的内容并重置它。
  • 如果函数失败,eof()的返回值为eof()。成功执行后,该函数返回与eof()不同的内容,并且通常使用作为参数传递的字符。由于参数可能是not_eof(),但仅仅返回参数是不够的:如果它是eof(),则需要将此值转换为其他有用的值,即{{1}确实:它返回参数,除非参数是sync(),在这种情况下它会返回一些合适的其他值。
  • 虚函数write()负责刷新缓冲区。在这种情况下,它首先检查是否有事要做,如果是,则写入缓冲区的内容。在这个函数中没有任何技巧,虽然我认为如果-1失败会更加谨慎,即返回的字符数少于缓冲区中的字符数。这个版本只是假装可以删除无法写入的字符,尽管它会指示错误。
  • 该函数仍然使用在缓冲区末尾留下一个字符空间的相同方法重置缓冲区。
  • 失败后,函数返回0,成功返回{{1}}。没有技巧。

答案 1 :(得分:0)

如果您使用C ++编写,则可以尝试使用STL<fstream>输出到文件中。它已经构建了缓冲区,并且没有速度问题。