2 Stimmen

Gibt es einen Grund, warum ein std::ofstream-Objekt nicht richtig geschlossen werden kann?

Ich habe in meinem C++-Code bemerkt, dass jedes Mal, wenn ich eine std::ofstream Objekt kann ich die Datei nicht wieder öffnen, die ich mit std::ifstream . std::ifstream 's open Funktion wird immer fehlschlagen.

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

Wahrscheinlich wird jemand nach meinem speziellen Code fragen, also habe ich ihn hier eingefügt, um diesen Beitrag klein zu halten aquí . In meinem Code werden nach dem Durchlaufen der Fälle a oder d alle std::ifstream offene Anrufe scheitern. (Bevor ich diese Frage gestellt habe, haben mehrere Personen mit meinem Code gespielt, die nichts anderes feststellen konnten, als dass std::ofstream Schließen aus unbekannten Gründen fehlgeschlagen)

Vielen Dank im Voraus für alle Antworten, die Sie erhalten.

Code ist

#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;

}

3voto

Steve Townsend Punkte 52288

Der beste Weg, um sicherzustellen, dass Ihre Streams an jedem Punkt dieser Verarbeitung zurückgesetzt werden, besteht darin, sie nicht explizit zu schließen, sondern sie am Punkt der Verwendung zu deklarieren und zuzulassen, dass sie aus dem Anwendungsbereich herausgehen. Dies ist der RAII-Punkt, der in den Kommentaren angesprochen wurde. In Ihrem Fall bedeutet dies, dass Sie die Deklaration vom Anfang der Funktion in jeden Zweig des Schalters verschieben, in dem sie verwendet werden. Auf diese Weise können Sie sicher sein, dass jede Datei sauber geschlossen wird, wenn Sie eine bestimmte Funktion verlassen. case da der ofstream und der ifstream die Datei beim Verlassen des Bereichs schließen.

Außerdem ist mir aufgefallen, dass Sie nach dem Öffnen der Datei eine seltsame Sache testen:

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

Dies testet auf einen schlechten Stream, aber ich glaube nicht, dass es vollständig ist - wenn Sie auf ein erfolgreiches Öffnen testen, sollten Sie auch testen

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

Alle Ihre Dateiverarbeitungsschleifen und open() Anrufe müssen geprüft werden auf fin.fail() ou fout.fail() wie auch fin.eof() um auszuschließen, dass der Dateizugriffsfehler eine unbehandelte Bedingung ist, die Ihr beobachtetes Verhalten verwirrt.

An dieser Stelle schlage ich vor, dass Sie diese offensichtlichen Missverständnisse beseitigen und mit spezifischeren Fragen zurückkommen, wenn Sie es nicht hinbekommen.

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