La forma correcta de leer un archivo de texto en C++ es while (std::getline(f, linea)). Aquí la tienes, junto con lo que suele salir mal: el bucle while (!f.eof()) que repite el último dato, los números que se dejan de leer sin avisar y el \r de los archivos creados en Windows.
También te puede interesar
Todos los programas de esta página leen archivos que están en la misma carpeta desde la que se ejecutan. El primero, notas.txt, tiene tres líneas:
cat notas.txt
salidaPrimera línea Segunda línea Tercera línea
La forma correcta: while (std::getline(f, linea))
#include <fstream>
#include <print>
#include <string>
int main()
{
std::ifstream f("notas.txt");
if (!f) {
std::println(stderr, "no se pudo abrir notas.txt");
return 1;
}
std::string linea;
int n = 0;
while (std::getline(f, linea)) {
std::println("{}: {}", ++n, linea);
}
}salida1: Primera línea 2: Segunda línea 3: Tercera línea
std::getline lee hasta el salto de línea, lo quita y devuelve el propio flujo, que se puede usar como condición: es cierto si la lectura salió bien. La lectura y la comprobación son la misma operación, así que el bucle se detiene justo cuando ya no queda nada. Y std::string crece lo que haga falta: no hay límite de longitud de línea ni riesgo de salirse de un búfer.
Fíjate también en el if (!f): si el archivo no existe o no hay permiso para leerlo, el ifstream no lanza ninguna excepción, solo queda en estado de error. Sin esa comprobación, el programa simplemente no imprimiría nada.
El bucle que no hay que escribir: while (!f.eof())
Este bucle aparece en miles de tutoriales, y la versión anterior de esta página lo usaba. Tiene dos errores a la vez:
#include <fstream>
#include <print>
#include <string>
int main()
{
std::ifstream f("notas.txt");
std::string palabra;
while (!f.eof()) {
f >> palabra;
std::println("[{}]", palabra);
}
}salida (incorrecta)[Primera] [línea] [Segunda] [línea] [Tercera] [línea] [línea]
- Lee palabras, no líneas. El operador
>>se detiene en cada espacio o salto de línea. - La última palabra sale dos veces.
eof()solo se vuelve cierto después de un intento de lectura que choca con el final. Tras leer «línea» todavía queda el último salto de línea, así que hay una vuelta de más: la lectura falla,palabraconserva lo que tenía y se imprime otra vez.
La versión original además leía en un char cadena[128]: una palabra de más de 127 caracteres se habría salido del array. Con std::string ese peligro desaparece. La regla es sencilla: comprueba la lectura, no el final del archivo.
Palabra a palabra y número a número
Si lo que quieres son palabras o números, usa >> como condición del bucle, igual que getline. Con números hay que distinguir entre «se acabó el archivo» y «había algo que no era un número». El archivo numeros.txt tiene una trampa en la segunda línea:
salida10 20 30 40 cuarenta 50
#include <fstream>
#include <print>
int main()
{
std::ifstream f("numeros.txt");
int n, suma = 0, leidos = 0;
while (f >> n) {
suma += n;
++leidos;
}
std::println("leídos {} números, suma {}", leidos, suma);
if (f.eof()) {
std::println("se llegó al final del archivo");
} else if (f.fail()) {
f.clear(); // quitar el estado de error para poder seguir leyendo
std::string intruso;
f >> intruso;
std::println("lectura detenida: «{}» no es un número", intruso);
}
}salidaleídos 4 números, suma 100 lectura detenida: «cuarenta» no es un número
Cuando >> no puede convertir lo que encuentra, activa failbit y deja de leer, aunque queden números detrás. Si no compruebas por qué terminó el bucle, sumas la mitad del archivo sin enterarte. Para datos de verdad suele ser mejor leer línea a línea y convertir cada campo con std::from_chars, que dice exactamente qué falló: lo explicamos en Trabajar con cadenas en C++.
Leer el archivo entero de una vez
#include <algorithm>
#include <fstream>
#include <print>
#include <sstream>
#include <stdexcept>
#include <string>
std::string leer_todo(const char* ruta)
{
std::ifstream f(ruta, std::ios::binary);
if (!f) {
throw std::runtime_error(std::string("no se pudo abrir ") + ruta);
}
std::ostringstream contenido;
contenido << f.rdbuf();
return contenido.str();
}
int main()
{
std::string texto = leer_todo("notas.txt");
std::println("{} bytes", texto.size());
std::println("{} saltos de línea", std::ranges::count(texto, '\n'));
try {
leer_todo("no-existe.txt");
} catch (const std::exception& e) {
std::println("error: {}", e.what());
}
}salida45 bytes 3 saltos de línea error: no se pudo abrir no-existe.txt
f.rdbuf() vuelca todo el archivo en el ostringstream de una vez. Son 45 bytes y no 42 caracteres porque la «í» de «línea» ocupa dos bytes en UTF-8: std::string cuenta bytes, no letras. Abrir en modo std::ios::binary evita que, en Windows, los finales de línea \r\n se conviertan al leer, así que obtienes el archivo tal cual está en el disco.
Archivos creados en Windows: el \r al final de cada línea
Los archivos de texto de Windows terminan cada línea con \r\n. En Linux y macOS, getline quita el \n pero deja el \r, invisible pero presente:
#include <fstream>
#include <print>
#include <string>
int main()
{
std::ifstream f("windows.txt");
std::string linea;
while (std::getline(f, linea)) {
bool trae_r = !linea.empty() && linea.back() == '\r';
if (trae_r) {
linea.pop_back();
}
std::println("[{}] {} caracteres, traía \\r: {}", linea, linea.size(), trae_r);
}
}salida[uno] 3 caracteres, traía \r: true [dos] 3 caracteres, traía \r: true [tres] 4 caracteres, traía \r: true
Sin ese pop_back(), comparar linea == "dos" daría falso y el error parecería inexplicable, porque al imprimir la línea el \r no se ve.
Errores típicos al leer archivos
- ErrorQué pasaSolución
while (!f.eof())Una vuelta de más: el último dato sale repetidowhile (std::getline(f, linea))owhile (f >> x)- No comprobar que el archivo se abrióEl programa no lee nada y no avisa
if (!f)justo después de abrir - Ruta relativaSe busca desde el directorio de trabajo, no desde donde está el ejecutableEjecutar desde la carpeta correcta o usar rutas absolutas
- Líneas de Windows en LinuxQueda un
\ral finalQuitarlo conpop_back() - Un dato que no es número
>>se detiene sin error visibleMirarfail()yeof()al salir, o leer líneas y convertir
La versión anterior de esta página terminaba con system("pause") para que la ventana de la consola de Windows no se cerrase. Ejecuta un programa externo solo para esperar una tecla, y en Linux y macOS esa orden no existe. Si ejecutas el programa desde una terminal abierta, no hace falta.
g++ -std=c++23 -Wall -Wextra leer.cpp -o leer && ./leer
Todo el código de esta página se compiló con GCC 15.3 (C++23, -std=c++23 -Wall -Wextra, sin avisos) y se ejecutó en Linux, en un contenedor limpio sin acceso a la red, antes de publicarla; las salidas están copiadas de esa ejecución.
¿Existe alguna forma de que los espacios no delimiten la lectura de la cadena?
void leerArchivo(){
string cadena;
ifstream datos(«Estructura.txt»);
if(datos.fail()){
cout<<"Texto entrada Estructura.txt no existe"<<endl;
}else{
while(!datos.eof()){
getline(datos,cadena); //con esta funcion tomas la linea(limitada por \n)
cout<<cadena<<endl;
}
}
}
haces dos getlines seguidos, osea lees la linea 2 pero no la guardas
¿Hay algún algoritmo que me deje leer una linea en especifico ? por ejemplo que lee solo la segunda linea del archivo.