Lea todo el archivo ASCII en C ++ std :: string

Necesito leer un archivo completo en la memoria y colocarlo en C ++ std::string .

Si tuviera que leerlo en un char[] , la respuesta sería muy simple:

 std::ifstream t; int length; t.open("file.txt"); // open input file t.seekg(0, std::ios::end); // go to the end length = t.tellg(); // report location (this is the length) t.seekg(0, std::ios::beg); // go back to the beginning buffer = new char[length]; // allocate memory for a buffer of appropriate dimension t.read(buffer, length); // read the whole file into the buffer t.close(); // close file handle // ... Do stuff with buffer here ... 

Ahora, quiero hacer exactamente lo mismo, pero usando std::string lugar de char[] . Quiero evitar bucles, es decir , no quiero:

 std::ifstream t; t.open("file.txt"); std::string buffer; std::string line; while(t){ std::getline(t, line); // ... Append line to buffer and go on } t.close() 

¿Algunas ideas?

Actualización: ¡ Resulta que este método, aunque sigue bien las expresiones idiomáticas STL, es sorprendentemente ineficiente! No hagas esto con archivos grandes. (Ver: http://insanecoding.blogspot.com/2011/11/how-to-read-in-file-in-c.html )

Puede hacer que un iterador streambuf esté fuera del archivo e inicializar la cadena con él:

 #include  #include  #include  std::ifstream t("file.txt"); std::string str((std::istreambuf_iterator(t)), std::istreambuf_iterator()); 

No estoy seguro de dónde obtiene la t.open("file.txt", "r") de. Por lo que sé, ese no es un método que std::ifstream tenga. Parece que lo has confundido con el fopen de C.

Editar: También tenga en cuenta los paréntesis adicionales alrededor del primer argumento para el constructor de cadenas. Estos son esenciales . Evitan el problema conocido como el ” análisis más irritante “, que en este caso no le dará un error de comstackción como suele hacerlo, pero le dará resultados interesantes (leer: incorrecto).

Siguiendo el punto de KeithB en los comentarios, aquí hay una manera de hacerlo que asigna toda la memoria por adelantado (en lugar de confiar en la reasignación automática de la clase de cadena):

 #include  #include  #include  std::ifstream t("file.txt"); std::string str; t.seekg(0, std::ios::end); str.reserve(t.tellg()); t.seekg(0, std::ios::beg); str.assign((std::istreambuf_iterator(t)), std::istreambuf_iterator()); 

Hay un par de posibilidades. Uno me gusta usar un stringstream como intermediario:

 std::ifstream t("file.txt"); std::stringstream buffer; buffer << t.rdbuf(); 

Ahora los contenidos de "file.txt" están disponibles en una cadena como buffer.str() .

Otra posibilidad (aunque ciertamente no me gusta) es mucho más parecida a tu original:

 std::ifstream t("file.txt"); t.seekg(0, std::ios::end); size_t size = t.tellg(); std::string buffer(size, ' '); t.seekg(0); t.read(&buffer[0], size); 

Oficialmente, esto no es necesario para trabajar bajo el estándar C ++ 98 o 03 (no se requiere cadena para almacenar datos contiguamente) pero de hecho funciona con todas las implementaciones conocidas, y C ++ 11 y posterior requieren almacenamiento contiguo , por lo que está garantizado para trabajar con ellos.

En cuanto a por qué no me gusta lo último también: primero, porque es más largo y más difícil de leer. En segundo lugar, porque requiere que inicialices el contenido de la cadena con datos que no te interesan, inmediatamente escribe esos datos (sí, el tiempo para inicializar suele ser trivial en comparación con la lectura, por lo que probablemente no importe) , pero para mí todavía se siente un poco mal). Tercero, en un archivo de texto, la posición X en el archivo no necesariamente significa que habrá leído X caracteres para llegar a ese punto; no es necesario tener en cuenta cosas como las traducciones de final de línea. En los sistemas reales que hacen tales traducciones (por ejemplo, Windows), el formulario traducido es más corto que el contenido del archivo (es decir, "\ r \ n" en el archivo se convierte en "\ n" en la cadena traducida) así que todo lo que ha hecho está reservado un poco de espacio extra que nunca usas. Una vez más, realmente no causa un problema importante, pero se siente un poco mal de todos modos.

Creo que la mejor manera es usar string stream. simple y rápido!

 ifstream inFile; inFile.open(inFileName);//open the input file stringstream strStream; strStream << inFile.rdbuf();//read the file string str = strStream.str();//str holds the content of the file cout << str << endl;//you can do anything with the string!!! 

Puede que no lo encuentres en ningún libro o sitio, pero descubrí que funciona bastante bien:

 ifstream ifs ("filename.txt"); string s; getline (ifs, s, (char) ifs.eof()); 

Pruebe uno de estos dos métodos:

 string get_file_string(){ std::ifstream ifs("path_to_file"); return string((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); } string get_file_string2(){ ifstream inFile; inFile.open("path_to_file");//open the input file stringstream strStream; strStream << inFile.rdbuf();//read the file return strStream.str();//str holds the content of the file } 

¡Me di cuenta de otra manera que funciona con la mayoría de las transmisiones isotérmicas, incluida std :: cin!

 std::string readFile() { stringstream str; ifstream stream("Hello_World.txt"); if(stream.is_open()) { while(stream.peek() != EOF) { str << (char) stream.get(); } stream.close(); return str.str(); } } 

Podría hacerlo así:

 void readfile(const std::string &filepath,std::string &buffer){ std::ifstream fin(filepath.c_str()); getline(fin, buffer, char(-1)); fin.close(); } 

Si esto es algo desagradable, por favor díganme por qué

Si usa glibmm , puede probar Glib :: file_get_contents .

 #include  #include  int main() { auto filename = "my-file.txt"; try { std::string contents = Glib::file_get_contents(filename); std::cout << "File data:\n" << contents << std::endl; catch (const Glib::FileError& e) { std::cout << "Oops, an error occurred:\n" << e.what() << std::endl; } return 0; } 

No creo que pueda hacer esto sin un bucle explícito o implícito, sin leer en una matriz de caracteres (o algún otro contenedor) primero y diez construyendo la cadena. Si no necesita las otras capacidades de una cadena, podría hacerlo con vector la misma manera que está utilizando actualmente un char * .