2015-03-05 16 views
5

Czy to dobry pomysł na czytanie w std::vector, czy jest jakiś haczyka tutaj:Odczyt pliku do wektora naraz

using namespace std; 
ifstream file("blah.dat", ios::binary); 

vector<T> v(N); 

file.read(static_cast<char*>(v.data()), N * sizeof(T)); 

Czy vector norma pozwala mi to zrobić, aby wypełnić wektor ? Dla uproszczenia załóżmy, że T jest zwykłym starym typem danych.

+0

'size_of' ==' sizeof'? Tak czy inaczej, pamiętaj, że rozmiar obiektu w pamięci niekoniecznie odpowiada rozmiarowi obiektu zapisanego w pliku (wypełnienie itp.) - to naprawdę zależy od tego, jak obiekt został napisany na początku. –

+0

@KonradRudolph: Dzięki, naprawione. Jeśli napisany w ten sposób (zły dla przenośności, w porządku dla mojego przypadku użycia) poprzez jednoznaczne zapisanie pamięci, powinien zostać odczytany w ten sposób. Jestem bardziej ciekawy części 'v.data'. –

+0

Powinieneś określić, czym jest 'T', aby uzyskać poprawne odpowiedzi. Czy to jest typ POD? –

Odpowiedz

2

Nie ma niezdefiniowanego zachowania tutaj, jeśli można łatwo kopiować T, co z pewnością stanowi POD. vector<T>::data gwarantuje zwrócenie wskaźnika do sąsiedniej tablicy vector<T>::sizeT s, a reprezentacja obiektu typu możliwego do kopiowania T gwarantuje ciągłą sekwencję bajtów sizeof(T) (ewentualnie z wewnętrznym dopełnieniem).

Jeśli bajty, które przechowujesz w tym miejscu, są nieprawidłowe T reprezentacji obiektów, możesz uzyskać niezdefiniowane zachowanie podczas uzyskiwania do nich dostępu. Dokładnie to, które sekwencje bajtów stanowią poprawną reprezentację obiektu, to trochę szarego obszaru; przynajmniej powinieneś być w stanie w przenośny sposób zapisać bazowe bajty obiektu o typie kopiowalnym trywialnie do pliku i skutecznie odczytać je z powrotem do bazowych bajtów obiektu tego samego typu.

Na litość paranoja jest, prawdopodobnie umieścić:

static_assert(std::is_trivially_copyable<T>(), 
       "NO NO NO - T MUST BE TRIVIALLY COPYABLE!"); 

przed file.read dla przyszłych-proofing.

0

Nie mają to zrobić, w rzeczywistości, co masz robić (od oryginalnego C++) jest to

std::ifstream file("foo.txt"); 
file >> std::noskipws;   // use this line so that whitespace won't be skipped 
std::vector<char> buffer(std::istream_iterator<char>(file), 
         std::istream_iterator<char>()); 

Powodem, dla którego nie masz robić to na swój sposób jest ponieważ nie ma sensu, aby obiekt znajdował się w pliku (przynajmniej w C++). Pliki zawierają tylko znaki, które są następnie formatowane przez operator>> w celu tworzenia obiektów. Standard umożliwia kompilatorowi wykonywanie naprawdę dziwnych rzeczy na obiekcie (szczególnie gdy włączono RTTI), co czyni go bezużytecznym dla "zapisania" obiektu do pliku. O wiele lepiej jest po prostu stworzyć własny format serializacji.

+2

'std :: istreambuf_iterator '. Twój przykład pominie spacje. – user657267

+0

Co jeśli to nie jest wektor "char"? Ponadto plik jest binarny. Czy możesz podać mi jakiś powód, dla którego nie powinienem tego robić? –

+0

@ user657267 Zobacz moją edycję dla tej korekty – randomusername

1

Wygląda na to, że skorzystasz z pliku odwzorowanego w pamięci. Funkcja Boost zapewnia dwie implementacje, więc nie musisz bezpośrednio mieszać z mmap().

Korzystanie boost.iostreams:

#include <boost/iostreams/device/mapped_file.hpp> 

boost::iostreams::mapped_file_source file("blah.dat"); 
std::size_t size = file.size()/sizeof(T); 
const T * ptr = reinterpret_cast<const T*>(file.data()); 
for (std::size_t i=0; i<size; ++i) 
    std::cout << ptr[i] << std::endl; 

Można również użyć boost.interprocess, ale wymaga więcej kodu na zasadzie takiej samej funkcjonalności.

Główną zaletą jest to, że nie można przydzielić pamięci w celu uzyskania dostępu do pliku, zostanie ona załadowana na żądanie w miarę uzyskiwania dostępu do danych. Same dane będą żyć w buforowanych/buforowanych stronach, więc nie zabierają żadnej pamięci (są odrzucane, jeśli system potrzebuje pamięci na coś innego.)

+0

Jakikolwiek sposób kontrolowania rozmiaru pamięci podręcznej? –

+0

Nie, wszystko jest obsługiwane przez system operacyjny; zazwyczaj będzie używać wszystkich wolnych stron jako pamięci podręcznej/buforów, ponieważ nie ma wiele do zyskania, pozostawiając pamięć RAM nieużywaną. Oznacza to, że jeśli twój system ma 8 GB i używane jest tylko 1,5 GB, to 6,5 GB będzie dostępne dla systemu operacyjnego dla buforowania. – DanielKO

+0

Oh: jeszcze jedno pytanie: jeśli dwa procesy próbują wykonać tylko do odczytu mmap na tym samym pliku, czy plik zostanie załadowany dwa razy? czy system operacyjny jest na tyle inteligentny, aby mapować go tylko raz? –