2010-10-30 37 views
2

J'ai remarqué dans mon code C++ qu'à chaque fois que je ferme un objet std::ofstream, je suis incapable de rouvrir le fichier que j'ai fermé avec std::ifstream. La fonction open échouera toujours.Une raison pour laquelle un objet std :: ofstream ne se fermera pas correctement?

Y a-t-il quelque chose de 'extra' que je puisse faire pour m'assurer que mon objet std :: ofstream se ferme correctement?

Quelqu'un va probablement demander à voir mon code spécifique donc pour le plaisir de garder ce post petit, je l'ai fait coller here. Dans mon code après avoir parcouru le cas a ou d tous les appels ouverts std::ifstream échouent. (Avant de poster cette question, j'avais plusieurs personnes qui jouaient avec mon code et qui étaient incapables de conclure quelque chose d'autre que std::ofstream fermer pour des raisons inconnues)

Merci d'avance pour toutes les réponses reçues.

code

est

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

} 
+0

Il serait utile de savoir quels objets de flux sont la cause de votre chagrin et à quelle ligne dans le code vous avez frappé l'erreur. –

+0

Dans mon code spécifiquement après je fout.close() je suis incapable de fin.open() –

+4

Nous aimons toujours garder le code dans la question de sorte que le poste SO est plus autonome et utile lorsque cette pâte meurt inévitablement. S'il vous plaît réduire à un test plus petit et inclure dans la question. –

Répondre

3

La meilleure façon de vous assurer que vos flux sont remis à zéro à chaque point de ce traitement est de ne pas les fermer explicitement, mais de les déclarer au point d'utilisation et leur permettre de sortir de portée. C'est le point RAII qui a été fait dans les commentaires. Dans votre cas, cela signifie déplacer la déclaration du haut de la fonction vers l'intérieur de chaque bras du commutateur où ils sont utilisés. De cette façon, vous pouvez être sûr que chaque fichier est fermé proprement lorsque vous quittez un case particulier, car le fichier d'aval et ifstream ferme le fichier lors de la destruction à la sortie de la portée.

Une autre chose que je remarque que vous testez une chose étrange après fichier ouvert:

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

Ce test pour un mauvais flux mais je ne pense pas qu'il soit complet - si vous testez pour une ouverture réussie , vous devez également tester

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

Toutes vos boucles de traitement de fichiers et open() appels doivent vérifier fin.fail() ou fout.fail() ainsi que fin.eof(), pour exclure les erreurs d'accès au fichier en tant que unhan dled condition qui confond votre comportement observé. À ce stade, je vous suggère de corriger ces malentendus évidents, et de revenir avec des questions plus précises si vous n'arrivez pas à le faire fonctionner.

+0

Merci, vos suggestions aident vraiment. –