2 Stimmen

Gibt es einen Grund warum ein std::ofstream-Objekt nicht ordnungsgemäß geschlossen wird?

Ich habe in meinem C++-Code bemerkt, dass jedes Mal, wenn ich ein std::ofstream-Objekt schließe, ich die Datei, die ich mit std::ifstream geschlossen habe, nicht wieder öffnen kann. Die open-Funktion von std::ifstream schlägt immer fehl.

Gibt es etwas 'extra', das ich tun kann, um sicherzustellen, dass mein std::ofstream-Objekt ordnungsgemäß geschlossen wird?

Jemand wird wahrscheinlich nach meinem spezifischen Code fragen, also um diesen Beitrag kurz zu halten, habe ich ihn hier gepostet. In meinem Code scheitern alle std::ifstream-Öffnungsaufrufe nach der Ausführung von Fall a oder d. (Bevor ich diese Frage gepostet habe, haben mehrere Personen meinen Code ausprobiert, konnten jedoch nichts anderes als das Scheitern von std::ofstream bei Schließen aus unbekannten Gründen feststellen)

Vielen Dank im Voraus für alle erhaltenen Antworten.

Der Code lautet

#include 
#include 
#include 

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 << "Willkommen bei der Adressbuch-Anwendung!" << endl << endl;
      cout << "\tWählen Sie eine Option:" << endl << endl;
      cout << "\tA -- Neuen Eintrag hinzufügen" << endl;
      cout << "\tD -- Eintrag löschen" << endl;
      cout << "\tS -- Nach einem vorhandenen Eintrag suchen" << endl;
      cout << "\tE -- Beenden" << endl << endl;

      cin >> input;

      switch(input)
      {
         case 'a':
         case 'A':
         cin.ignore(255,'\n');//Offenbar erforderlich, da eine zusätzliche neue Zeile im cin-Stream übertragen wird
         system("cls");
         //Informationen vom Benutzer abrufen
         cout << "Telefonnummer eingeben: ";
         getline(cin, buffer.Phone);
         cout << endl << "Name eingeben: ";
         getline(cin, buffer.Name);
         cout << endl << "Adresse eingeben: ";
         getline(cin, buffer.Address);
         /* Bestehende Datenbank in einen Puffer kopieren. Mit anderen Worten, ein Backup erstellen */
         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();
            /* Puffer in neue Datenbankdatei kopieren */
            ibuffer.open("buffer.txt");
            fout.open("address.txt");//Dadurch werden alle zuvor vorhandenen Informationen aus database.txt gelöscht
            while(ibuffer && ibuffer.get(ch))
               fout.put(ch);
            ibuffer.close();
            remove("buffer.txt");//Puffer löschen
            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');//Offenbar erforderlich, da eine zusätzliche neue Zeile im cin-Stream übertragen wird
         system("cls");
         cout << "Geben Sie die Telefonnummer des zu löschenden Eintrags ein: ";
         cin >> stringinput;
         fin.open("address.txt");
         if(!fin)
         {
            cout << endl << "Keine Einträge vorhanden!";
            fin.close();
            break;
         }
         obuffer.open("buffer.txt");
         /* Alles in den Puffer kopieren, außer dem Konto, das wir löschen möchten */
         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));//Überflüssiges '\n' entfernen
                  stringoutput.erase();
               }

            }

         }

         //Hack: Die letzte Zeile kopieren, da die Schleife aus irgendeinem Grund nicht funktioniert
         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 << "Eintrag " << stringinput << " erfolgreich gelöscht!" << endl;
         stringinput.erase();
         stringoutput.erase();
         break;

         case 's':
         case 'S':
         cin.ignore(255,'\n');//Offenbar erforderlich, da eine zusätzliche neue Zeile im cin-Stream übertragen wird
         system("cls");

         found = false;

         fin.open("address.txt");
         if(!fin)
         {
            cout << "Keine Einträge vorhanden!" << endl << endl;
            fin.close();
            break;
         }

         cout << "Geben Sie die Telefonnummer ein, nach der gesucht werden soll: ";
         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 << "Telefonnummer: " << stringinput << endl;
            getline(fin, stringoutput);
            cout << "Name: " << stringoutput << endl;
            getline(fin, stringoutput);
            cout << "Adresse: " << stringoutput << endl << endl;
         }

         if(!found)
         {
            stringoutput.erase();
            cout << endl << stringinput << " ist nicht im Adressbuch enthalten!" << endl << endl;
         }

         stringinput.erase();
         stringoutput.erase();
         fin.close();
         break;

         case 'e':
         case 'E':
         exit = true;
         break;

         default:
         system("cls");
         cout << input << " ist keine gültige Option." << endl << endl;
         break;
      }

   }

   return 0;

}

3voto

Steve Townsend Punkte 52288

Der beste Weg, um sicherzustellen, dass Ihre Streams an jeder Stelle in diesem Verarbeitungsprozess zurückgesetzt werden, besteht nicht darin, sie explizit zu schließen, sondern sie an der Verwendungsstelle zu deklarieren und zuzulassen, dass sie den Gültigkeitsbereich verlassen. Dies ist der RAII-Punkt, der in den Kommentaren gemacht wurde. In Ihrem Fall bedeutet dies, die Deklaration vom Anfang der Funktion in jeden Zweig des Switch zu verschieben, wo sie verwendet werden. Auf diese Weise können Sie sicher sein, dass jede Datei sauber geschlossen wird, wenn Sie aus einem bestimmten case herauskommen, da die ofstream und ifstream die Datei beim Verlassen des Gültigkeitsbereichs während der Zerstörung schließen.

Eine weitere Sache, die mir aufgefallen ist, ist, dass Sie nach dem Öffnen der Datei eine seltsame Überprüfung durchführen:

fin.open("address.txt");
if (!fin)

Dies überprüft auf einen ungültigen Stream, aber ich denke, es ist nicht vollständig - wenn Sie auf eine erfolgreiche Öffnung testen, sollten Sie auch überprüfen

fin.open("address.txt");
if (!fin.is_open())

All Ihre Dateiverarbeitungsschleifen und open()-Aufrufe müssen auch auf fin.fail() oder fout.fail() sowie auf fin.eof() überprüfen, um File-Zugriffsfehler als eine unbehandelte Bedingung auszuschließen, die Ihr beobachtetes Verhalten verwirrt.

An diesem Punkt schlage ich vor, dass Sie diese offensichtlichen Missverständnisse beheben und mit konkreteren Fragen wiederkommen, wenn Sie es nicht zum Laufen bringen können.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X