Ich implementiere meine eigene streambuf-Klasse zum Schreiben komprimierter Ausgabedateien. Hier, wie es aussieht.Probleme beim Schreiben eines benutzerdefinierten streambuf für gezippte Streams
template <class T>
class gzstreambufbase : public std::streambuf
{
protected:
static const int bufferSize = 8192;
public:
gzstreambufbase();
~gzstreambufbase();
bool close();
bool is_open();
protected:
virtual T* open(const std::string& name, std::ios::openmode mode) = 0;
virtual int sync();
// flush the characters in the buffer
int flush_buffer();
protected:
gzFile filePtr_;
std::ios::openmode mode_;
bool opened_;
char buffer_[bufferSize];
std::string fileName_;
};
Dann von dieser Basis neue igzstreambuf
und ogzstreambuf
Klassen zur Ein- und Ausgabe streambufs entsprechend ich abzuleiten. Im Grunde wurde die Implementierung durchgeführt, indem man dem Beispiel von Nicolai M. Josuttis [C++ Standardbibliothek, The: A Tutorial and Reference] folgte.
Schauen wir uns nur die ogzstream
Implementierung an.
ogzstreambuf::ogzstreambuf()
{
// initialize data buffer
// one character less to let the bufferSizeth
// character cause a call of overflow()
setp(buffer_, buffer_ + (bufferSize - 1));
}
ogzstreambuf*
ogzstreambuf::open(const std::string& name, std::ios::openmode mode)
{
if (is_open())
return (ogzstreambuf*)0;
mode_ = mode;
fileName_ = name;
filePtr_ = gzopen(fileName_.c_str(), "wb");
CUSTOM_CHECK(0 != filePtr_, ("GZIP_IO_ERROR", strerror(errno)));
opened_ = 1;
return this;
}
std::streampos
ogzstreambuf::seekpos(std::streampos offset, std::ios_base::openmode which)
{
return seekImpl(offset, std::ios_base::beg, which);
}
std::streampos
ogzstreambuf::seekoff(std::streamoff offset, std::ios_base::seekdir way, std::ios_base::openmode which)
{
return seekImpl(offset, way, which);
}
std::streampos
ogzstreambuf::seekImpl(std::streamoff offset, std::ios_base::seekdir way, std::ios_base::openmode which)
{
assert(!fileName_.empty(), "");
assert(LONG_MAX != offset, "");
assert(std::ios_base::out == which, "");
assert(way != std::ios_base::end,
"zlib doesn't support the value SEEK_END in gzseek().");
if (!flush_buffer())
return std::streampos(EOF);
const long newPos = gzseek(filePtr_, offset,
(way == std::ios_base::beg ? SEEK_SET : SEEK_CUR));
CUSTOM_CHECK((long) offset == newPos, ("GZIP_IO_ERROR", strerror(errno)));
setp(buffer_, buffer_ + (bufferSize - 1));
return offset;
}
So ist das Problem, dass der Anruf von tellp()
auf meinem eigenen umgesetzt ogzstream
Objekt (das eine Instanz von ogzstreambuf
intern hält) -1(EOF)
Wert zurückgibt, da:
Intern wenn Mitglied FAIL Wahr, die Funktion gibt -1 zurück. Sonst gibt es
rdbuf()->pubseekoff(0,cur,out)
zurück;
Zitiert von cpp. Und schließlich flush_buffer()
kehrt 0
weil pptr() - pbase();
-0
gleich ist:
template <class T>
int gzstreambufbase<T>::flush_buffer()
{
// Separate the writing of the buffer from overflow() and
// sync() operation.
int w = pptr() - pbase();
if (gzwrite(filePtr_, pbase(), w) != w)
return EOF;
pbump(-w); // reset put pointer acccordingly
return w;
}
Als Ergebnis pubseekoff()
kehrt EOF
und tellp()
ausfällt. Ich möchte verstehen, was ich bei der Implementierung verpasst habe und was ich tun sollte, um diese Umsetzung zu verbessern.
Wenn Sie nicht bereits vertraut sind, könnte es sich lohnt, Boost io_streams Anlage zu betrachten, gibt es einen komprimierten Stream, der der Pipeline hinzugefügt werden kann, lesen/schreiben - es ist ein netter Ansatz .. – Nim
@Nim, eigentlich habe ich versucht, etwas ähnliches wie boost_io_streams (mit Pipeline) zu implementieren. Hier ist meine andere Frage: [Link] (http://stackoverflow.com/questions/37627112/writing-gzipped-output-file-without-extra-disk-space-with-pipe) –
@Nim, BTW, brauche ich ein suchbarer gzipped stream und wie ich in boost :: iostreams weiß filtering_stream 'funktioniert nicht mit' gzip_compressor() ':) –