c++ - 如何将写入缓冲区添加到io.h中定义的写入中

标签 c++ buffer

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

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

最佳答案

创建缓冲基础结构并不是真正的火箭科学,但也不是完全无关紧要的。就个人而言,我只是创建一个从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()获得的无效字符的值进行比较。 traits类型的所有成员都是statictypedef,即无需使用此类型的对象。当使用traits_type的不同模板实例时,std::basic_streambuf的使用很重要。
尽管缓冲区通常在两端之间是pbase()epptr()且在pptr()之间,但可以使用pptr()epptr()移到pbump(n)之外:此功能只是将n添加到pptr()。这用于在调用sync()之前将currecnt字符放入缓冲区中,而overflow()只是写入缓冲区的内容并将其重置。
如果函数失败,则返回eof()eof()。成功执行后,该函数将返回与eof()不同的值,并且通常使用作为参数传递的字符。因为参数可能是eof(),但是仅仅返回参数是不够的:但是,如果它是not_eof(),则需要将该值转换为eof()所做的其他有用的值:它将返回它参数,除非参数为sync(),在这种情况下它将返回一些合适的其他值。
虚函数write()负责刷新缓冲区。在这种情况下,首先要检查是否有要做的事情,如果是,则写入缓冲区的内容。尽管我猜如果-1失败的话,一个适当的技巧会更加小心,即返回的字符少于缓冲区中的字符,但实际上并没有任何技巧。这个版本只是假装可以松散无法写入的字符,尽管这将指示错误,但可以。
该函数仍使用与在缓冲区末尾保留一个字符空间相同的方法来重置缓冲区。
失败时,函数返回0,成功时,函数返回。没戏

关于c++ - 如何将写入缓冲区添加到io.h中定义的写入中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9234792/

相关文章:

c++ - cv::Mat 到 QImage 并返回

android - 在 Eclipse 上通过缓冲区使用 AudioTrack 缓冲区播放音乐 - 没有声音

iphone - 应用程序处于后台状态时 AVPlayer 处理缓冲区

java - 了解为什么 Java 模式与缓冲的 .java 文件中的不正确文本相匹配?

wordpress - ob_start() 和 ob_get_clean() 的使用

c++ - 哪个编译器对于以下重载/特化行为是正确的?

C++我误解了输出参数吗

c++ - 我的 'next offset' 算法中的错误 - C++

c++ - 检查数据库中的指纹

Java缓冲策略失去硬件加速