我在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);
}
};
答案 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
获得的无效字符的值进行比较。特征类型的所有成员都是typedef
或traits_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>
输出到文件中。它已经构建了缓冲区,并且没有速度问题。