Die Boost C++ Bibliotheken

Filter

Neben Devices bietet Boost.IOStreams Filter an. Sie werden vor Devices gesetzt, um Daten, die von Devices gelesen oder in Devices geschrieben werden, zu filtern. In den folgenden Beispielprogrammen wird dazu auf die Klassen boost::iostreams::filtering_istream und boost::iostreams::filtering_ostream zugegriffen. Die Klassen ersetzen boost::iostreams::stream, da diese Klasse keine Filter unterstützt.

Beispiel 34.6. Daten mit boost::iostreams::regex_filter filtern
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/regex.hpp>
#include <boost/regex.hpp>
#include <iostream>

using namespace boost::iostreams;

int main()
{
  char buffer[16];
  array_sink sink{buffer};
  filtering_ostream os;
  os.push(regex_filter{boost::regex{"Bo+st"}, "C++"});
  os.push(sink);
  os << "Boost" << std::flush;
  os.pop();
  std::cout.write(buffer, 3);
}

Im Beispiel 34.6 wird das Device boost::iostreams::array_sink verwendet, um Daten in ein Array zu schreiben. Die Daten sollen durch einen Filter vom Typ boost::iostreams::regex_filter geschickt werden, der Zeichen ersetzen kann. Dieser Filter erwartet einen regulären Ausdruck und eine Formatierung. Der reguläre Ausdruck beschreibt, was ersetzt werden soll. Die Formatierung gibt an, durch was die gefundenen Zeichen ersetzt werden sollen. Im Beispiel soll Boost durch C++ ersetzt werden. Dabei kann Boost mit einem oder mehreren o geschrieben werden.

Der Filter und das Device werden mit Hilfe des Streams boost::iostreams::filtering_ostream verknüpft. Diese Klasse bietet eine Methode push() an, der der Filter und das Device übergeben werden.

Beachten Sie, dass zuerst der Filter und dann das Device übergeben wird. Die Reihenfolge ist entscheidend. Sie können ein oder mehrere Filter mit push() übergeben. Wird ein Device übergeben, ist der Stream vollständig, und Sie dürfen push() kein weiteres Mal aufrufen.

Der Filter boost::iostreams::regex_filter kann Daten nicht schrittweise verarbeiten. Er kann Zeichen nicht einzeln filtern, da er auf einem regulären Ausdruck basiert und Zeichengruppen betrachten muss. Daher wird boost::iostreams::regex_filter erst aktiv, wenn ein Schreibvorgang abgeschlossen ist und alle Daten vorliegen. Dies ist der Fall, wenn ein Device mit pop() vom Stream entfernt wird. Im Beispiel 34.6 wird diese Methode aufgerufen, nachdem Boost in den Stream geschrieben wurde. Ohne den Aufruf von pop() würde boost::iostreams::regex_filter keine Daten verarbeiten und daher auch keine Daten an das Device weiterleiten.

Beachten Sie, dass Sie einen Stream nicht verwenden dürfen, wenn er nicht mit einem Device verknüpft ist. Sie können den Stream jedoch jederzeit wieder vervollständigen, wenn Sie nach dem Aufruf von pop() mit push() ein Device hinzufügen.

Wenn Sie Beispiel 34.6 ausführen, wird C++ ausgegeben.

Beispiel 34.7. Auf Filter in boost::iostreams::filtering_ostream zugreifen
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/counter.hpp>
#include <iostream>

using namespace boost::iostreams;

int main()
{
  char buffer[16];
  array_sink sink{buffer};
  filtering_ostream os;
  os.push(counter{});
  os.push(sink);
  os << "Boost" << std::flush;
  os.pop();
  counter *c = os.component<counter>(0);
  std::cout << c->characters() << '\n';
  std::cout << c->lines() << '\n';
}

Beispiel 34.7 verwendet den Filter boost::iostreams::counter, der Zeichen und Zeilen zählt. Die Klasse bietet entsprechend die beiden Methoden characters() und lines() an.

Um auf einen Filter zugreifen zu können, stellt boost::iostreams::filtering_stream die Methode component() zur Verfügung. Ihr muss der Index des entsprechenden Filters als Parameter übergeben werden. Da es sich bei component() außerdem um ein Template handelt, muss der Typ des entsprechenden Filters als Template-Parameter angegeben werden. component() gibt einen Zeiger auf den entsprechenden Filter zurück. Der Zeiger ist 0, wenn ein falscher Filtertyp als Template-Parameter angegeben wird.

Im Beispiel 34.7 werden fünf Zeichen in den Stream geschrieben. Keines davon ist ein \n. Daher gibt das Programm 5 und 0 aus.

Beispiel 34.8. Mit ZLIB komprimierte Daten schreiben und lesen
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/zlib.hpp>
#include <vector>
#include <string>
#include <iostream>

using namespace boost::iostreams;

int main()
{
  std::vector<char> v;
  back_insert_device<std::vector<char>> snk{v};
  filtering_ostream os;
  os.push(zlib_compressor{});
  os.push(snk);
  os << "Boost" << std::flush;
  os.pop();

  array_source src{v.data(), v.size()};
  filtering_istream is;
  is.push(zlib_decompressor{});
  is.push(src);
  std::string s;
  is >> s;
  std::cout << s << '\n';
}

Im Beispiel 34.8 kommt neben boost::iostreams::filtering_ostream der Stream boost::iostreams::filtering_istream zum Einsatz. Dieser wird verwendet, um Daten mit Filtern zu lesen. So sollen in diesem Beispiel Daten komprimiert geschrieben und wieder gelesen werden.

Boost.IOStreams bietet zahlreiche Filter zur Datenkompression an. Die Klasse boost::iostreams::zlib_compressor kann verwendet werden, um Daten im ZLIB-Format zu komprimieren. Um im ZLIB-Format komprimierte Daten zu entpacken, wird die Klasse boost::iostreams::zlib_decompressor verwendet. Die Filter werden entsprechend mit push() den Streams hinzugefügt.

Wenn Sie Beispiel 34.8 ausführen, wird Boost komprimiert in den Vektor v geschrieben und dekomprimiert in den String s gelesen. Das Programm gibt daher Boost auf die Standardausgabe aus.

Anmerkung

Beachten Sie, dass Boost.IOStreams unter Windows die Komprimierung mit ZLIB standardmäßig nicht unterstützt. Bei Boost.IOStreams handelt es sich um eine vorkompilierte Bibliothek, die unter Windows mit dem Makro NO_ZLIB erstellt wird. Sie müssen Makros wie ZLIB_LIBPATH und ZLIB_SOURCE setzen, um ZLIB-Unterstützung unter Windows zu erhalten.

Aufgabe

Entwickeln Sie zwei Programme, mit denen eine Datei komprimiert und wieder entpackt werden kann.