Cualquier razón por la cual un objeto std :: ofstream no se cerrará correctamente?
-
27-09-2019 - |
Pregunta
he notado en mi código C ++ que en cualquier momento de cerrar un objeto std::ofstream
soy incapaz de volver a abrir el archivo que cerraba con std::ifstream
. std::ifstream
función de open
siempre fallará.
¿Hay algo 'extra' que puede hacer para asegurar que mi objeto std :: ofstream cierre correctamente?
Alguien probablemente va a pedir ver mi código específico de lo que en aras de mantener este pequeño post me he pastied que aquí . En mi código después de correr a través de un caso o d todo std::ifstream
llamadas abiertas fallan. (Antes de la publicación de esta pregunta que había varias personas jugar con mi código que no pudieron llegar a la conclusión que no sea std::ofstream
estrecha en su defecto por razones desconocidas nada)
Gracias de antemano a cualquier y todas las respuestas recibidas.
El código es
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
typedef struct Entry
{
string Name;
string Address;
string Phone;
};
int main()
{
bool exit = false, found = false;
char input, ch;
string stringinput, stringoutput;
ifstream fin, ibuffer;
ofstream fout, obuffer;
Entry buffer;
while(!exit)
{
cout << "Welcome to the Address Book Application!" << endl << endl;
cout << "\tSelect an option:" << endl << endl;
cout << "\tA -- Add New Entry" << endl;
cout << "\tD -- Delete an Entry" << endl;
cout << "\tS -- Search for an Existing Entry" << endl;
cout << "\tE -- Exit" << endl << endl;
cin >> input;
switch(input)
{
case 'a':
case 'A':
cin.ignore(255,'\n');//Apparently necessary because an extra new line carrys over in the cin stream
system("cls");
//Get Information from User
cout << "Enter Phone Number: ";
getline(cin, buffer.Phone);
cout << endl << "Enter Name: ";
getline(cin, buffer.Name);
cout << endl << "Enter Address: ";
getline(cin, buffer.Address);
/*Copy existing database into a buffer. In other words, back it up*/
fin.open("address.txt");
if(!fin)
{
fin.close();
fout.open("address.txt");
fout << buffer.Phone << endl << buffer.Name << endl << buffer.Address << endl;
}
if(fin)
{
obuffer.open("buffer.txt");
while(fin && fin.get(ch))
obuffer.put(ch);
fin.close();
obuffer.close();
/*Copy buffer to new database file*/
ibuffer.open("buffer.txt");
fout.open("address.txt");//This removes all of the previously existing info from database.txt
while(ibuffer && ibuffer.get(ch))
fout.put(ch);
ibuffer.close();
remove("buffer.txt");//Delete the buffer
fout << endl << buffer.Phone << endl << buffer.Name << endl << buffer.Address << endl;
}
buffer.Phone.erase();
buffer.Name.erase();
buffer.Address.erase();
fout.close();
break;
case 'd':
case 'D':
cin.ignore(255,'\n');//Apparently necessary because an extra new line carrys over in the cin stream
system("cls");
cout << "Enter the phone number of the entry to delete: ";
cin >> stringinput;
fin.open("address.txt");
if(!fin)
{
cout << endl << "No entries exist!";
fin.close();
break;
}
obuffer.open("buffer.txt");
/* Copy everything over into the buffer besides the account we wish to delete */
while(!fin.eof())
{
fin.read(&ch, sizeof(char));
if(ch != '\n' && ch != '\0')
stringoutput += ch;
if(ch == '\n' || ch == '\0')
{
if(stringinput.compare(stringoutput))
{
stringoutput += ch;
obuffer << stringoutput;
stringoutput.erase();
}
if(!stringinput.compare(stringoutput))
{
stringoutput += ch;
getline(fin, stringoutput);
getline(fin, stringoutput);
fin.read(&ch, sizeof(char));//Get rid of the extra '\n'
stringoutput.erase();
}
}
}
//Hack: Copy the last line over since the loop for some reason doesn't
obuffer << stringoutput;
stringoutput.erase();
fin.close();
obuffer.close();
fout.open("address.txt");
ibuffer.open("buffer.txt");
while(ibuffer && ibuffer.get(ch))
fout.put(ch);
ibuffer.close();
fout.close();
remove("buffer.txt");
cout << endl << "Entry " << stringinput << " deleted successfully!" << endl;
stringinput.erase();
stringoutput.erase();
break;
case 's':
case 'S':
cin.ignore(255,'\n');//Apparently necessary because an extra new line carrys over in the cin stream
system("cls");
found = false;
fin.open("address.txt");
if(!fin)
{
cout << "No entries currently exist!" << endl << endl;
fin.close();
break;
}
cout << "Enter the phone number to search for: ";
cin >> stringinput;
while(!fin.eof())
{
fin.read(&ch, sizeof(char));
if(ch != '\n' && ch != '\0')
stringoutput += ch;
if(ch == '\n' || ch == '\0')
{
if(!stringinput.compare(stringoutput))
{
found = true;
break;
}
stringoutput.erase();
}
}
if(found)
{
cout << "Phone Number: " << stringinput << endl;
getline(fin, stringoutput);
cout << "Name: " << stringoutput << endl;
getline(fin, stringoutput);
cout << "Address: " << stringoutput << endl << endl;
}
if(!found)
{
stringoutput.erase();
cout << endl << stringinput << " is not in the address book!" << endl << endl;
}
stringinput.erase();
stringoutput.erase();
fin.close();
break;
case 'e':
case 'E':
exit = true;
break;
default:
system("cls");
cout << input << " is not a valid option." << endl << endl;
break;
}
}
return 0;
}
Solución
La mejor manera de asegurarse de que sus corrientes se ponen a cero en cada punto de este tratamiento es que no se cierren de manera explícita, sino para declarar en el punto de uso y les permiten salir de su ámbito. Este es el punto RAII que se hizo en los comentarios. En su caso este medio de mover el declaraion desde la parte superior de la función para el interior de cada brazo del interruptor donde se utilizan. De esta manera usted puede estar seguro de que cada archivo se cierra limpiamente cuando se sale de una case
en particular, como el ofstream y ifstream cierre el archivo durante la destrucción en la salida ámbito de aplicación.
Otra cosa que he notado es que se está probando una cosa extraña después de abrir el archivo:
fin.open("address.txt");
if(!fin)
Esta prueba de una mala corriente, pero no creo que esté completo - si está probando para una exitosa abierta, también debe de prueba
fin.open("address.txt");
if (!fin.is_open())
Todos los bucles de procesamiento de archivos y las llamadas open()
necesita verificar la fin.fail()
o fout.fail()
, así como fin.eof()
, para descartar errores de acceso a archivos como una condición no controlada que es confusa su comportamiento observado.
En este punto, le sugiero a solucionar estos malentendidos obvios, y volver con más preguntas específicas si no se puede conseguir que funcione.