std :: ofstream对象不能正确关闭的任何原因? [英] Any reason why an std::ofstream object won't close properly?

查看:254
本文介绍了std :: ofstream对象不能正确关闭的任何原因?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我注意到在我的C ++代码,任何时候我关闭 std :: ofstream 对象我无法重新打开我关闭的文件 std :: ifstream std :: ifstream 打开函数将总是失败。

I noticed in my C++ code that anytime I close an std::ofstream object I'm unable to reopen the file I closed with std::ifstream. std::ifstream's open function will always fail.

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

Is there anything 'extra' I can do to ensure that my std::ofstream object closes properly?

有人可能会要求看到我的具体代码,为了保持这个帖子小,我已经这里。在我的代码中,在运行通过case a或d全部 std :: ifstream 打开调用失败。 (在发布这个问题之前,我有几个人玩我的代码谁不能总结除了 std :: ofstream 关闭失败由于未知的原因)

Someone's probably going to ask to see my specific code so for the sake of keeping this post small I've pastied it here. In my code after running through case a or d all std::ifstream open calls fail. (Prior to posting this question I had several people play with my code who were unable to conclude anything other than that std::ofstream close failing for unknown reasons)

感谢所有收到的回复。

代码是

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

}


推荐答案

确保您的流在此处理中的每个点处重置的方式不是显式地关闭它们,而是在使用点处声明它们,并允许它们超出范围。这是评论中提出的RAII观点。在你的情况下,这意味着将声明从函数的顶部移动到使用它们的交换机的每个臂内。这种方式你可以确保,当你退出一个特定的 case 时,每个文件被干净地关闭,因为ofstream和ifstream关闭范围退出破坏期间的文件。

The best way to ensure your streams are reset at each point in this processing is not to explicitly close them, but to declare them at the point of use and allow them to go out of scope. This is the RAII point that was made in comments. In your case this means moving the declaraion from the top of the function to inside each arm of the switch where they are used. This way you can be sure that each file is cleanly closed when you exit from a particular case, as the ofstream and ifstream close the file during destruction on scope exit.

我注意到的另一件事是,你在文件打开后测试一个奇怪的事情:

Another thing I noticed is that you are testing a strange thing after file open:

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

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

This tests for a bad stream but I don't think it's complete - if you are testing for a successful open, you should also test

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

所有文件处理循环和 open()调用需要检查 fin.fail() fout.fail 以及 fin.eof(),以排除文件访问错误作为一个未处理的条件,混淆您的观察行为。

All of your file processing loops and open() calls need to check for fin.fail() or fout.fail() as well as fin.eof(), to rule out file access error as an unhandled condition that is confusing your observed behaviour.

在这一点上,我建议你解决这些明显的误解,如果你不能工作,回来更具体的问题。

At this point, I suggest you fix these obvious misunderstandings, and come back with more specific questions if you cannot get it working.

这篇关于std :: ofstream对象不能正确关闭的任何原因?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆