Ho bisogno di copiare un file in una stringa. Ho bisogno in qualche modo di preallocare la memoria per quell'oggetto stringa e un modo per leggere direttamente il contenuto del file nella memoria di quella stringa?come pre-allocare memoria per un oggetto std :: string?
risposta
std::string
also has a .reserve
method.
Questo dovrebbe essere tutto ciò che serve:
ostringstream os;
ifstream file("name.txt");
os << file.rdbuf();
string s = os.str();
Questa legge i caratteri da file
e li inserisce nel stringstream. Successivamente ottiene la stringa creata dietro le quinte. Si noti che sono caduto nella seguente trappola: l'utilizzo dell'operatore di estrazione salterà lo spazio vuoto iniziale. Devi usare l'operatore di inserimento come sopra, o utilizzare il noskipws
manipolatore:
// Beware, skips initial whitespace!
file >> os.rdbuf();
// This does not skip it
file >> noskipws >> os.rdbuf();
Queste funzioni sono descritte come leggere il carattere flusso per carattere anche se (non so cosa le ottimizzazioni sono possibili qui, però), Mi rifugio' t cronometrati per determinare la loro velocità.
+1 mi picchia. :( – GManNickG
questo copia due volte, una volta al buffer 'ostringstream' e la seconda volta a' s' –
@Johannes, stavo assumendo che la memoria delle stringhe fosse un buffer contagioso, ma dopo aver letto la risposta di @GMan mi sono reso conto che non c'è –
Solo per divertimento, ecco un altro modo per farlo:
// Beware, brain-compiled code ahead!
std::ifstream ifs(/* ... */);
if(!ifs.good()) return; // whatever
std::string str;
ifs.seekg(0, std::ios_base::end);
const std::streampos pos = ifs.tellg();
ifs.seekg(0, std::ios_base::beg);
if(pos!=std::streampos(-1)) // can get stream size?
str.reserve(static_cast<std::string::size_type>(pos));
str.assign(std::istream_iterator<char>(ifs)
, std::istream_iterator<char>());
spero non mi soffiare troppo male.
+1, aspettavo che qualcuno elaborasse il codice basato su iteratore in streaming :) – bobah
+1, per 'Brain-Compilatore flessibile 'è ok con mancante'} ';) –
@Gollum: Ammetto che ho copiato queste righe 'seekg()' direttamente da un mio codice (che riempie una stringa con il contenuto di un file) e ho trascurato il '{'. L'ho risolto, ma è per quello che è il disclaimer. – sbi
Questa non è tanto una risposta in sé, come una sorta di commento/riassunto/confronto di un paio di altre risposte (oltre a una rapida dimostrazione del perché ho raccomandato lo stile del codice @ Johannes - litb cede nella sua risposta). Dal momento che @sbi ha pubblicato un'alternativa che sembrava abbastanza buona, e (soprattutto) ha evitato la copia extra coinvolta nella lettura in uno stringstream, quindi usando il membro .str()
per ottenere una stringa, ho deciso di scrivere un rapido confronto tra i due:
[Modifica: ho aggiunto un terzo test case usando il codice basato su @Tyler McHenry istreambuf_iterator
e aggiunto una riga per stampare la lunghezza di ogni stringa che è stata letta per garantire che l'ottimizzatore non ottimizzasse la lettura perché il risultato non è mai stato utilizzato]
[Edit2:. E ora, è stato aggiunto il codice da Martin York, nonché ...]
#include <fstream>
#include <sstream>
#include <string>
#include <iostream>
#include <iterator>
#include <time.h>
int main() {
std::ostringstream os;
std::ifstream file("equivs2.txt");
clock_t start1 = clock();
os << file.rdbuf();
std::string s = os.str();
clock_t stop1 = clock();
std::cout << "\ns.length() = " << s.length();
std::string s2;
clock_t start2 = clock();
file.seekg(0, std::ios_base::end);
const std::streampos pos = file.tellg();
file.seekg(0, std::ios_base::beg);
if(pos!=std::streampos(-1))
s2.reserve(static_cast<std::string::size_type>(pos));
s2.assign(std::istream_iterator<char>(file), std::istream_iterator<char>());
clock_t stop2 = clock();
std::cout << "\ns2.length = " << s2.length();
file.clear();
std::string s3;
clock_t start3 = clock();
file.seekg(0, std::ios::end);
s3.reserve(file.tellg());
file.seekg(0, std::ios::beg);
s3.assign((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
clock_t stop3 = clock();
std::cout << "\ns3.length = " << s3.length();
// New Test
std::string s4;
clock_t start4 = clock();
file.seekg(0, std::ios::end);
s4.resize(file.tellg());
file.seekg(0, std::ios::beg);
file.read(&s4[0], s4.length());
clock_t stop4 = clock();
std::cout << "\ns4.length = " << s3.length();
std::cout << "\nTime using rdbuf: " << stop1 - start1;
std::cout << "\nTime using istream_iterator: " << stop2- start2;
std::cout << "\nTime using istreambuf_iterator: " << stop3 - start3;
std::cout << "\nTime using read: " << stop4 - start4;
return 0;
}
Ora la parte impressionante - i risultati. Prima con VC++ (nel caso qualcuno se ne frega, il codice di Martin è abbastanza veloce ho aumentato la dimensione del file per ottenere un tempo significativo per esso):
s.length() = 7.669.436
s2.length = 6.390.688
s3.length = 7669436
s4.lunghezza = 7669436
Ora utilizzando rdbuf: 184
Ora utilizzando istream_iterator: 1332
Ora utilizzando istreambuf_iterator: 249
Ora utilizzando leggere: 48
Poi con gcc (cygwin):
s.length() = 8278035
s2.length = 6390689
s3.length = 8278035
s4.length = 8.278.035
Tempo usando rdbuf: 62
Tempo usando istream_iterator: 2199
Tempo usando istreambuf_iterator: 156
tempo con leggere: 16
[fine della modifica - le conclusioni rimangono, anche se il vincitore è cambiato - il codice di Martin è chiaramente il più veloce è. ]
I risultati sono abbastanza coerenti rispetto ai quali è il più veloce e il più lento. L'unica incoerenza riguarda il modo in cui molto più veloce o più lento di uno. Sebbene i posizionamenti siano gli stessi, le differenze di velocità sono molto più grandi di con gcc che con VC++.
Ordinamento di ciò che pensavo inizialmente: è molto più semplice ottimizzare la lettura char-by-char di op << in una lettura blocco (o inline parti appropriate) rispetto alla lettura char-by-char di istream_iterator (sebbene tale codice debba usa 'istreambuf_iterator' per evitare di saltare lo spazio bianco per ogni carattere letto - forse questo accelera le cose da quando sta accadendo a un livello inferiore?), che va su più passaggi con op ++, op * ecc. Ma non mi aspettavo che avrebbe reso * quella * molta differenza. Grazie per il tempismo! –
Potresti scrivere quali flag di compilazione sono stati utilizzati per i casi di test? – tomekpe
Sembra che tu stia chiedendo come eseguire un'operazione di tipo CString :: GetBuffer, ReleaseBuffer con std :: string.
Non conosco alcun modo per farlo direttamente, un modo semplice sarebbe semplicemente creare un buffer di stile C grezzo, leggere nel buffer, quindi copiare il buffer in una stringa: std :: assign o qualunque . Ovviamente dovresti preoccuparti dei problemi di sovraccarico del buffer, ecc. Vorrei usare anche uno std :: autoptr per gestire il puntatore del buffer raw, enusre deallocation su exception ecc. Questo è un po 'più semplice dell'uso di stringstream ecc. Posso fornire un esempio se necessario.
Devin Ellingson
'auto_ptr' non gestisce correttamente i tipi di array. Basta usare 'std :: vector'. (Inoltre, la firma dei post è disapprovata, il tuo nome è sotto tutto quello che fai.) – GManNickG
Grazie a GMan, ho dimenticato questo problema, auto_ptr chiama sempre delete anziché delete [], che è ciò che sarebbe necessario in questo caso. Si potrebbe semplicemente creare una semplice classe array_auto_ptr o come dici usare std :: vector. – DevinEllingson
- 1. Devo preallocare std :: stringstream?
- 2. SWIG: come avvolgere std :: string & (std :: string passato per riferimento)
- 3. Memoria libera utilizzata da uno std :: string
- 4. equivalente strncpy per std :: string?
- 5. preallocare spazio di memoria per i programmi di utilizzare
- 6. Restituisce un oggetto std :: string C++ protetto da perdite di memoria?
- 7. Differenza tra std: string e std :: string
- 8. Come trasformare System :: String^in std :: string?
- 9. Come preallocare (prenotare) un priority_queue <vector>?
- 10. Come std :: find utilizzando un oggetto Confronta?
- 11. Considerate preallocare per la velocità
- 12. restituendo std :: string/std :: lista da dll
- 13. Posso fare in modo che std :: string usi meno memoria?
- 14. Perché non è std :: string :: max_size() == std :: string :: allocator :: max_size()
- 15. Perché non esiste un costruttore di riserva per std :: string?
- 16. std :: string o std :: vector per conservare i dati grezzi
- 17. std :: string a LPCTSTR
- 18. std :: string :: iterator per offset e back
- 19. Come ottenere un oggetto Date da String
- 20. std :: string x (x);
- 21. prestazioni std :: strstr vs. std :: string :: trovare
- 22. Come ottenere System.IO.Stream da un oggetto String
- 23. C'è un modo per std :: move std :: string in std :: stringstream
- 24. C++ È uno std :: string un contenitore?
- 25. ordinamento dipendente dalla locale per std :: string
- 26. std :: vector <std::string> crash
- 27. Interpreta std :: string come std :: vector di char_type?
- 28. (non) utilizzando std :: string in eccezioni
- 29. Does std :: string :: chiaro e std :: list :: chiaro cancella i dati dalla memoria
- 30. Come convertire std :: string al V8 locale <string>
possibile duplicato di [Read intero file ASCII in C++ std :: string] (http://stackoverflow.com/questions/2602013/read-whole-ascii-file-into-c-stdstring) - La mia risposta accettata a questa domanda spiega anche come pre-allocare tutta la memoria in modo che la stringa non si espanda ripetutamente durante la lettura. –