我在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类型的所有成员都是static
或typedef
,即无需使用此类型的对象。当使用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/