2012-05-31 6 views
10

Ich versuche, eine Datei in den Speicher zu mappen und dann Zeile für Zeile analysieren - ist istream, was ich verwenden soll?ispersonam vs Speicherzuordnung einer Datei?

Ist itsream das gleiche wie das Mappen einer Datei in den Arbeitsspeicher von Windows? Ich hatte Schwierigkeiten, ein vollständiges Beispiel für das Mappen einer Datei in den Speicher zu finden.

Ich habe Leute gesehen, die Memory Mapping Artikel von msdn verlinken, aber wenn jemand ein kleines (~ 15 Zeilen?) Beispiel empfehlen könnte, wäre ich sehr willkommen.

Ich muss die falsche Sache suchen, aber bei der Suche "C++ Memory Mapping Beispiel" auf Google konnte ich kein Beispiel finden, die durch Iterieren durch.

Dies waren die nächsten Ergebnisse (nur, damit die Menschen erkennen, ich ausgesehen haben): http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2044.html#ClassSharedMemoryObjectExample

http://msdn.microsoft.com/en-us/library/dd997372.aspx (kein C++ Code)

http://beej.us/guide/bgipc/output/html/multipage/mmap.html (wurde für Unix glaube ich, keine Fenster)

+3

"* Ich versuche eine Datei in den Speicher zu mappen und ** dann ** zeilenweise zu analysieren *". Können Sie uns sagen, warum Sie die Datei im Speicher abbilden möchten? Warum ist es nicht ausreichend, Zeile für Zeile zu analysieren (zB 'ifstream' oder' fopen')? –

+3

@Rob, rein aus Leistungsgründen. Ich war unter dem (falschen?) Eindruck, dass es schneller die ganze Datei abbildet? – user997112

+2

@ user997112: Es hängt davon ab, was Sie mit den Daten machen. Wenn Sie es für einen geeigneten Parser verwenden, der Backtracking implementiert, sind Dateien mit Memory-Mapping um ein Vielfaches schneller. Aber wenn Sie nur durch die Daten vorwärts iterieren (wie bei mehreren einfachen 'std :: getline'-Aufrufen), bezweifle ich, dass es einen merklichen Unterschied geben wird. Sicherlich gibt es kein _harm_ bei der Verwendung einer speicherabgebildeten Datei, es sei denn, Sie haben nur wenig Platz im virtuellen Adressraum (wahrscheinlich nur ein Problem in 32-Bit-Code mit GB + Dateigrößen). – ildjarn

Antwort

11

std::istream ist ein abstrakter Typ – Sie können es nicht direkt verwenden. Sie sollten streambuf mit einem benutzerdefinierten daraus wurden Ableiten-Array gesichert:

#include <cstddef> 
#include <string> 
#include <streambuf> 
#include <istream> 

template<typename CharT, typename TraitsT = std::char_traits<CharT>> 
struct basic_membuf : std::basic_streambuf<CharT, TraitsT> { 
    basic_membuf(CharT const* const buf, std::size_t const size) { 
     CharT* const p = const_cast<CharT*>(buf); 
     this->setg(p, p, p + size); 
    } 

    //... 
}; 

template<typename CharT, typename TraitsT = std::char_traits<CharT>> 
struct basic_imemstream 
: virtual basic_membuf<CharT, TraitsT>, std::basic_istream<CharT, TraitsT> { 
    basic_imemstream(CharT const* const buf, std::size_t const size) 
    : basic_membuf(buf, size), 
     std::basic_istream(static_cast<std::basic_streambuf<CharT, TraitsT>*>(this)) 
    { } 

    //... 
}; 

using imemstream = basic_imemstream<char>; 

char const* const mmaped_data = /*...*/; 
std::size_t const mmap_size = /*...*/; 
imemstream s(mmaped_data, mmap_size); 
// s now uses the memory mapped data as its underlying buffer. 

Wie für das Memory-Mapping selbst, empfehle ich Boost.Interprocess für diesen Zweck verwendet:

#include <cstddef> 
#include <string> 
#include <boost/interprocess/file_mapping.hpp> 
#include <boost/interprocess/mapped_region.hpp> 

namespace bip = boost::interprocess; 

//... 

std::string filename = /*...*/; 
bip::file_mapping mapping(filename.c_str(), bip::read_only); 
bip::mapped_region mapped_rgn(mapping, bip::read_only); 
char const* const mmaped_data = static_cast<char*>(mapped_rgn.get_address()); 
std::size_t const mmap_size = mapped_rgn.get_size(); 

-Code für entnommen von this answer von Dietmar Kühl.

+2

Woher kommt die Eingabe von mmaped_data? Wir brauchen einen Verweis auf die Datei, die ich vermute? – user997112

+1

@ user997112: Das hängt davon ab, auf welcher Plattform Sie sind - Standard-C++ bietet keine Speicher-Mapped-Dateien. Auf * nix gibt es 'mmap'; Unter Windows gibt es 'CreateFileMapping'. Persönlich verwende ich [Boost.Interprocess] (http://www.boost.org/libs/interprocess/) 's Memory Mapped Files, da sie plattformübergreifend sind; Ich werde in einem Beispiel dafür bearbeiten. – ildjarn

+0

Vielen Dank, sehr zu schätzen – user997112

1

Ist itsream das gleiche wie das Mappen einer Datei in den Arbeitsspeicher von Windows?

Nicht genau. Sie sind nicht im selben Sinne gleich, ein "Stream" ist keine "Datei".

Denken Sie an eine Datei als gespeicherte Sequenz und an einen Stream als Schnittstelle für den "Kanal" (ein Stream_Buffer), der beim Übergang von seinem Speicher zu den empfangenden Variablen fließt.

Denken Sie an eine Memory-Mapped-Datei als eine "Datei", die - außerhalb der Verarbeitungseinheit gespeichert - im Speicher synchron gespeichert wird. Es hat den Vorteil, dass es als roher Speicherpuffer als Datei sichtbar ist. Wenn Sie es als Stream lesen möchten, ist der einfachste Weg wahrscheinlich, einen istringstream zu verwenden, der diesen rohen Puffer als Speicherort hat.

+0

Um ehrlich zu sein würde ich lieber die ganze Datei auf einmal lesen, im Gegensatz zu einem Stream – user997112

+0

@ user997112: Es hängt davon ab, was Sie mit seinem Inhalt tun werden. Wenn die Datei ein Text ist und Sie welche Nummern zu lesen sind, müssen Sie sie irgendwie analysieren. Der std :: isotream (und abgeleitet) sind nur dieser Parser. –