代码之家  ›  专栏  ›  技术社区  ›  Rob S.

为什么std::ofstream对象不能正确关闭?

  •  2
  • Rob S.  · 技术社区  · 14 年前

    std::ofstream 对象我无法重新打开用关闭的文件 std::ifstream 标准::ifstream open

    有什么“额外的”我可以做,以确保我的std::ofstream对象正确关闭?

    可能有人会要求查看我的特定代码,所以为了保持这篇文章的小规模,我粘贴了它 here . 在我的代码中运行完案例a或d之后 打开呼叫失败。(在发布这个问题之前,我有几个人在玩弄我的代码,他们无法得出除此之外的任何结论。) 流标准::ofstream

    提前感谢所有收到的回复。

    代码是

    #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;
    
    }
    
    1 回复  |  直到 14 年前
        1
  •  3
  •   Steve Townsend    14 年前

    确保流在处理过程中的每个点都重置的最佳方法不是显式地关闭它们,而是在使用点声明它们并允许它们超出范围。这是在评论中提出的问题。在您的例子中,这意味着将声明从函数的顶部移动到使用它们的开关的每个臂的内部。这样,当您从特定的 case ,因为ofstream和ifstream在作用域退出时销毁文件。

    我注意到的另一件事是,打开文件后,您正在测试一个奇怪的东西:

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

    这测试一个不好的流,但我不认为它是完整的-如果你正在测试一个成功的开放,你也应该测试

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

    open() 电话需要检查 fin.fail() fout.fail() 以及 fin.eof()

    在这一点上,我建议你纠正这些明显的误解,如果你不能让它起作用的话,再来问一些更具体的问题。