2011-01-21 16 views
34

Me gustaría evitar copias innecesarias. Estoy apuntando a algo en la línea de:Manera eficiente de leer un archivo en un estándar :: vector <char>?

std::ifstream testFile("testfile", "rb"); 
std::vector<char> fileContents; 
int fileSize = getFileSize(testFile); 
fileContents.reserve(fileSize); 
testFile.read(&fileContents[0], fileSize); 

(que no funciona porque reserve en realidad no introduzca nada en el vector, por lo que no se puede acceder [0]).

Por supuesto, std::vector<char> fileContents(fileSize) funciona, pero hay una sobrecarga de inicialización de todos los elementos (fileSize puede ser bastante grande). Lo mismo para resize().

Esta pregunta no se trata tanto de cuán importante sería esa sobrecarga. Por el contrario, solo tengo curiosidad por saber si hay otra manera.

+1

Si desea evitar el costo de reasignación requerido por 'push_back' _and_ desea evitar el costo de poner a cero el búfer requerido al usar' resize', no use un 'std :: vector' en absoluto: use un 'boost :: scoped_array' o algo similar. –

Respuesta

54

La forma canónica es la siguiente:

#include<iterator> 
// ... 

std::ifstream testFile("testfile", std::ios::binary); 
std::vector<char> fileContents((std::istreambuf_iterator<char>(testFile)), 
           std::istreambuf_iterator<char>()); 

Si usted está preocupado por las reasignaciones a continuación, reservar espacio en el vector:

#include<iterator> 
// ... 

std::ifstream testFile("testfile", std::ios::binary); 
std::vector<char> fileContents; 
fileContents.reserve(fileSize); 
fileContents.assign(std::istreambuf_iterator<char>(testFile), 
        std::istreambuf_iterator<char>()); 
+0

¿No harán eso reasignaciones mientras el vector está creciendo? (Dado que los iteradores pueden no admitir la resta, el constructor no puede determinar el tamaño por adelantado). – Thomas

+0

Sí, lo haría. Si eso es realmente una preocupación, reserve y use 'std :: copy()'. Actualizado. – wilhelmtell

+0

En el segundo ejemplo, 'reserve' debe ser' resize', no? –

0

Si lo entiendo correctamente, quiere leer cada elemento pero no desea cargarlo todo en el fileContents, ¿correcto? Personalmente, no creo que esto haga copias innecesarias porque abrir archivos varias veces disminuiría más el rendimiento. Leer una vez en un vector fileContents es una solución razonable en este caso.

+0

No quise votar esto, pero está bloqueado. Si editas la respuesta, puedo/eliminaré el voto a la baja. – ditkin

5

Si quieren verdadera lectura de copia cero, es decir, a elimine la copia del kernel al espacio del usuario, simplemente asigne el archivo a la memoria. Escriba su propio contenedor de archivos asignado o use uno de boost::interprocess.

Cuestiones relacionadas