2016-06-09 7 views
0

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.

+1

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

+0

@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) –

+0

@Nim, BTW, brauche ich ein suchbarer gzipped stream und wie ich in boost :: iostreams weiß filtering_stream 'funktioniert nicht mit' gzip_compressor() ':) –

Antwort

0

Nach dem richtigen Debugging, habe ich selbst endlich das Problem gefunden. Es musste nur überprüft werden, EOF == flush_buffer() anstelle von !flush_buffer() ...

Verwandte Themen