it-swarm.com.de

Wie lese ich Dateiinhalte in istringstream ein?

Um die Leseleistung einer Datei zu verbessern, versuche ich, den gesamten Inhalt einer großen Datei (mehrere MB) in den Speicher zu lesen und dann einen Istringstream zu verwenden, um auf die Informationen zuzugreifen.

Meine Frage ist, wie diese Informationen am besten gelesen und in den String-Stream "importiert" werden können. Ein Problem bei diesem Ansatz (siehe unten) ist, dass beim Erstellen des String-Streams die Puffer kopiert werden und sich die Speichernutzung verdoppelt.

#include <fstream>
#include <sstream>

using namespace std;

int main() {
  ifstream is;
  is.open (sFilename.c_str(), ios::binary );

  // get length of file:
  is.seekg (0, std::ios::end);
  long length = is.tellg();
  is.seekg (0, std::ios::beg);

  // allocate memory:
  char *buffer = new char [length];

  // read data as a block:
  is.read (buffer,length);

  // create string stream of memory contents
  // NOTE: this ends up copying the buffer!!!
  istringstream iss( string( buffer ) );

  // delete temporary buffer
  delete [] buffer;

  // close filestream
  is.close();

  /* ==================================
   * Use iss to access data
   */

}
36
Marcos Bento

std::ifstream Hat eine Methode rdbuf(), die einen Zeiger auf eine filebuf zurückgibt. Sie können diese filebuf dann in Ihre stringstream "pushen":

#include <fstream>
#include <sstream>

int main()
{
    std::ifstream file( "myFile" );

    if ( file )
    {
        std::stringstream buffer;

        buffer << file.rdbuf();

        file.close();

        // operations on the buffer...
    }
}

EDIT: Wie Martin York in den Kommentaren bemerkt, ist dies möglicherweise nicht die schnellste Lösung, da der stringstreamoperator<< Des Dateibuf zeichenweise liest. Vielleicht möchten Sie seine Antwort überprüfen, wobei er wie gewohnt die Methode ifstreamread verwendet, und dann den Puffer stringstream so einstellen, dass er auf den zuvor zugewiesenen Wert zeigt Erinnerung.

41
Luc Touraille

IN ORDNUNG. Ich sage nicht, dass dies schneller geht als das Lesen aus der Datei

Dies ist jedoch eine Methode, bei der Sie den Puffer einmal erstellen und nach dem Einlesen der Daten in den Puffer direkt als Quelle für den Stringstream verwenden.

N.B.Erwähnenswert ist, dass der std :: ifstream gepuffert ist. Es liest Daten aus der Datei in (relativ großen) Blöcken. Stream-Operationen werden für den Puffer ausgeführt und kehren nur dann zum erneuten Lesen in die Datei zurück, wenn weitere Daten benötigt werden. Vergewissern Sie sich vor dem Speichern aller Daten, dass es sich um einen Flaschenhals handelt.

#include <fstream>
#include <sstream>
#include <vector>

int main()
{
    std::ifstream       file("Plop");
    if (file)
    {
        /*
         * Get the size of the file
         */
        file.seekg(0,std::ios::end);
        std::streampos          length = file.tellg();
        file.seekg(0,std::ios::beg);

        /*
         * Use a vector as the buffer.
         * It is exception safe and will be tidied up correctly.
         * This constructor creates a buffer of the correct length.
         *
         * Then read the whole file into the buffer.
         */
        std::vector<char>       buffer(length);
        file.read(&buffer[0],length);

        /*
         * Create your string stream.
         * Get the stringbuffer from the stream and set the vector as it source.
         */
        std::stringstream       localStream;
        localStream.rdbuf()->pubsetbuf(&buffer[0],length);

        /*
         * Note the buffer is NOT copied, if it goes out of scope
         * the stream will be reading from released memory.
         */
    }
}
41
Martin York

Dies scheint mir eine vorzeitige Optimierung zu sein. Wie viel Arbeit wird in der Verarbeitung getan. Unter der Annahme eines modernen Desktops/Servers und nicht eines eingebetteten Systems ist das Kopieren einiger MB Daten während der Initialisierung relativ kostengünstig, insbesondere im Vergleich zum erstmaligen Auslesen der Datei von der Festplatte. Ich würde mich an das halten, was Sie haben, das System messen, wenn es fertig ist, und entscheiden, ob sich die potenziellen Leistungssteigerungen lohnen würden. Wenn der Speicher knapp ist, befindet sich dies natürlich in einer inneren Schleife oder in einem Programm, das häufig aufgerufen wird (etwa einmal pro Sekunde) und das Gleichgewicht ändert.

1
KeithB

Beachten Sie auch, dass Datei-E/A immer die langsamste Operation ist. Die Lösung von Luc Touraille ist richtig, aber es gibt noch andere Möglichkeiten. Das gleichzeitige Einlesen der gesamten Datei in den Speicher ist viel schneller als das separate Einlesen.

0
luke