2012-05-31 23 views
10

Próbuję odwzorować plik na pamięć, a następnie analizować linię po linii - czy jest to, co powinienem użyć?istream vs memory mapowanie pliku?

Czy to jest tak samo jak odwzorowywanie pliku w pamięci w systemie Windows? Miałem trudności z odnalezieniem pełnego przykładu mapowania pliku do pamięci.

Widziałem ludzi łączących artykuły mapowania pamięci z msdn, ale jeśli ktoś mógłby polecić mały (~ 15 liniowy) przykład, byłbym bardzo mile widziany.

Muszę wyszukiwać niewłaściwe rzeczy, ale podczas wyszukiwania "przykład mapowania pamięci C++" w google nie mogłem znaleźć przykładu, który obejmował iterowanie.

Były najbliższymi wyniki (tak ludzi zdaje sobie sprawę Szukałem): http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2044.html#ClassSharedMemoryObjectExample

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

http://beej.us/guide/bgipc/output/html/multipage/mmap.html (był dla Unix wierzę, nie windows)

+3

"* Próbuję odwzorować plik w pamięci i ** następnie ** przeanalizować wiersz po linii *". Czy możesz nam powiedzieć, dlaczego chcesz mapować plik na pamięć? Dlaczego parsowanie line-by-line (przy użyciu, powiedzmy, 'ifstream' lub' fopen') nie jest wystarczające? –

+3

@Rob, wyłącznie z powodów związanych z wydajnością. Byłem pod wrażeniem (fałsz?), Że szybciej odwzorowuje cały plik? – user997112

+2

@ user997112: To zależy od tego, co zrobisz z danymi. Jeśli używasz go do poprawnego parsera, który implementuje backtracking, pliki mapowane w pamięci są bezspornie szybsze; ale jeśli po prostu przechodzisz do przodu przez dane (tak jak w przypadku wielu prostych wywołań 'std :: getline'), wątpię, aby wystąpiła jakakolwiek zauważalna różnica. Z pewnością nie ma mowy o używaniu pliku odwzorowanego w pamięci, chyba że brakuje ci wirtualnej przestrzeni adresowej (prawdopodobnie tylko problem w 32-bitowym kodzie z plikami rozmiaru GB +). – ildjarn

Odpowiedz

11

std::istream jest abstrakcyjnym typem – którego nie można użyć bezpośrednio. Powinieneś być z niej wynikające z niestandardowych array-backed streambuf:

#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. 

Co do samej pamięci-mapping, polecam stosując Boost.Interprocess do tego celu:

#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(); 

kodeksu imemstream pobrane z this answer przez Dietmar Kühl.

+2

skąd pochodzi dane wejściowe z mmaped_data? Potrzebujemy odniesienia do pliku, który zakładam? – user997112

+1

@ user997112: To zależy od platformy, na której się znajdujesz - standardowe C++ nie udostępnia plików odwzorowanych w pamięci. On * nix, istnieje 'mmap'; w systemie Windows istnieje 'CreateFileMapping'. Osobiście używam plików odwzorowanych w pamięci [Boost.Interprocess] (http://www.boost.org/libs/interprocess/), ponieważ są one wieloplatformowe; Będę edytować w tym przykładzie. – ildjarn

+0

Dziękuję, doceń to bardzo – user997112

1

Czy to jest to samo, co mapowanie pliku do pamięci w systemie Windows?

Niezupełnie. Nie są tożsame w tym samym sensie, że "strumień" nie jest "plikiem".

Pomyśl o pliku jako sekwencji przechowywanej i strumieniu jako interfejsie dla "kanału" (bufora strumieniowego), którego sekwencja przepływa podczas przechodzenia ze swojego magazynu do zmiennych przyjmujących.

Pomyśl o zmapowanym pliku jako "pliku", który - zamiast być przechowywany poza jednostką przetwarzania - jest przechowywany w zsynchronizowanej pamięci. Ma tę zaletę, że jest widoczny jako bufor pamięci surowej będący plikiem. Jeśli chcesz odczytać go jako strumień, najprostszym sposobem jest prawdopodobnie użycie istringstream, który ma ten surowy bufor jako miejsce do czytania.

+0

Szczerze mówiąc wolałbym czytać cały plik naraz, w przeciwieństwie do strumienia – user997112

+0

@ user997112: To zależy od tego, co zrobisz z jego zawartością. Jeśli plik jest tekstem, a ty, co chcesz odczytać, musisz go jakoś przeanalizować. Std :: istream (i wyprowadzone) są właśnie tym parserem. –