Stream-Buffers

Die eigentliche Hauptarbeit beim Einlesen von Daten aus einem std::istream geschieht unter der Haube in dem zugehörigen Streambuffer. Das Beispiel zeigt, wie das in etwa aussieht.

Video

Quellcode

#include <fstream>
#include <iostream>

class my_ifstream
{
    std::basic_filebuf<char> m_filebuf;
    bool m_error;
    std::streamsize m_gcount;

public:
    
    my_ifstream(char const * const fname)
       : m_gcount{ 0 }
    {
        m_filebuf.open(fname, std::ios_base::in);
        m_error = !m_filebuf.is_open();
    }
    
    ~my_ifstream()
    {
        if (m_filebuf.is_open()) {
            m_filebuf.close();
        }
    }
    
    my_ifstream &read(char *buffer, std::streamsize max_bytes)
    {
        m_gcount = m_filebuf.sgetn(buffer, max_bytes);
        if (m_gcount < max_bytes) {
            m_error = true;
        }
        return *this;
    }
    
    std::streamsize gcount() const
    {
        return m_gcount;
    }
    
    operator bool() const
    {
        return m_filebuf.is_open() && !m_error;
    }
};

int main(int, char *argv[])
{
    my_ifstream i { argv[1] };
    char buffer[100];
    int loops = 0;
    std::streamsize bytes = 0;
    do
    {
        i.read(buffer, 100);
        bytes += i.gcount();
        ++loops;
    } while (i);
    std::cout << "Datei wurde in " << loops << " Durchgängen gelesen und enthält " 
              << bytes << " Bytes.\n";
}

Erklärung

Der im Beispiel verwendete std::filebuf ist eine mögliche Implementierung des generischen std::streambuf, die Dateien einliest. Zu diesem Zweck bietet das Objekt eine Methode zum Öffnen von Dateien an (std::filebuf::open, Zeile 15). Um zu prüfen, ob die Datei offen ist, kann die Methode is_open() verwendet werden (Zeile 16). Diese prüft, ob das entsprechende filebuf-Objekt mit einer geöffneten Datei verbunden wurde. Das trifft noch keine Aussage darüber, ob diese Datei auch gelesen werden kann, sondern beantwortet nur die Frage, ob die Datei erfolgreich geöffnet werden konnte (bspw. ob die Datei gefunden wurde und man die entsprechenden Berechtigungen hat).

Um eine Menge an Bytes aus der Datei auszulesen findet die Methode filebuf::sgetn() Verwendung. Sie erhält einen Pointer auf einen Puffer, in dem die gelesenen Zeichen abzulegen sind und die Anzahl an Zeichen, die zu lesen sind. Die Methode versucht dann, die geforderte Anzahl einzulesen. Sie liefert die Anzahl der tatsächlich gelesenen Zeichen zurück. Die Implementierung von my_ifstream::read hier im Beispiel interpretiert eine Anzahl < der geforderten als Fehler und setzt entsprechend das Fehlerbit im Stream-Objekt.