【问题标题】:Fstream fails to create new fileFstream 无法创建新文件
【发布时间】:2011-06-15 22:49:55
【问题描述】:

我正在为一个项目使用 FileManager,这样阅读和写作对我来说就不那么麻烦了。或者,如果我没有花所有时间调试它。所以,这个舒适班实际上给我带来了压力和时间。惊人的。

问题似乎是fstream。在继续之前,这是我的 FileManager 类的结构。

class FileManager : Utility::Uncopyable
{
public:
    FileManager();

    void open(std::string const& filename);
    void close();

    void read(std::string& buffer);
    void write(std::string const& data);

private:
    std::fstream stream_;
};

非常简单。缓冲区在读取函数期间加载数据,数据参数是要写入文件的内容。在读取和写入之前,您必须打开文件,否则可能会遇到一个大而胖的异常。有点像我现在得到的那个。

场景:用户的简单命令行注册,然后将数据写入文件。我要一个名字和密码。名称被复制并附加 .txt(文件名)。所以它看起来像这样:

void SessionManager::writeToFile(std::string const& name, 
                                 std::string const& password)
{
    std::string filename = name + ".txt";
    std::string data;
    data += name +", " +password;

    try
    {
        fileManager_->open(filename);
        fileManager_->write(data);
        fileManager_->close();
    } 
    catch(FileException& exception)
    {
        /* Clean it up. */
        std::cerr << exception.what() << "\n";
        throw;
    }
}

问题:打开失败。该文件永远不会创建,并且在写入期间我因为没有打开文件而出现异常。

FileManager::open() 函数:

void FileManager::open(std::string const& filename)
{
    if(stream_.is_open())
        stream_.close();

    stream_.open(filename.c_str());
}

然后写

void FileManager::write(std::string const& data)
{
    if(stream_.is_open())
        stream_ << data;
    else
        throw FileException("Error. No file opened.\n");
}

但是,如果我事先创建了文件,那么打开文件就没有问题了。然而,当我检查时,默认的std::ios::openmodestd::ios::in | std::ios::out。当我只标记std::ios::out 时,我可以很好地创建文件,但我想保持流处于读/写状态。

我怎样才能做到这一点?

【问题讨论】:

    标签: c++ file file-io


    【解决方案1】:

    最佳方法:

    void FileManager::open(std::string const& filename)
    {
        using std::ios_base;
        if( stream_.is_open() )
            stream_.close();
    
        stream_.open( filename.c_str() ); // ...try existing file
        if( !stream_.is_open() ) // ...else, create new file...
            stream_.open(filename.c_str(), ios_base::in | ios_base::out | ios_base::trunc);
    }
    

    因此代码会测试现有文件,如果没有,则创建它。

    【讨论】:

      【解决方案2】:

      您必须使用明确的 openmode 参数调用 fstream::open

      ios_base::in | ios_base::out | ios_base::trunc
      

      否则open 会因为ENOENT 而失败。

      C++ 标准草案的表 95 列出了可能的文件打开模式及其在stdio 中的等效模式。默认情况下,ios_base::out | ios_base::inr+。我上面列出的那个相当于w+ios_base::out | ios_base::app 等价于 a。涉及ios_base::app 的所有其他组合均无效。

      (有被嘲笑的风险:您可以切换到stdio并使用文件模式a+,它从头读取并在末尾附加。)

      【讨论】:

      • 自 C++11 起,ios_base::app 本身是允许的,相当于“a”。更新后的表请参见 C++11 或 C++14 中的表 132。
      【解决方案3】:

      您不能在不存在的文件上使用std::ios::in。使用

      std::ios::in | std::ios::out | std::ios::trunc
      

      改为(但请确保它不存在,否则将被截断为零字节)。

      【讨论】:

        【解决方案4】:

        我怎样才能做到这一点?

        std::ofstream file("file.txt");
        file << data;
        

        这不是更简单吗?

        【讨论】:

        • 我承认我在这个 FileManager 类中看不到重点,但 OP 想要一个读/写流。
        【解决方案5】:

        这就是库的工作方式:std::ios::in | std::ios::out 以等效于stdio"r+" 的方式打开它,即它只会打开现有文件。我不相信有一种模式可以满足您的需求,您必须向我们提供特定于操作系统的调用或检查文件是否存在(再次使用特定于操作系统的调用)并以一种模式打开它或另一个取决于它是否已经存在。

        编辑:我假设您不希望文件已存在时被截断。正如其他人所指出的,如果您愿意截断任何现有文件,那么in | out | trunc 是一个选项。

        【讨论】:

          【解决方案6】:

          让你的功能打开

          void FileManager::open(std::string const& filename)
          {
              using std::ios_base;
              if(stream_.is_open())
                  stream_.close();
          
              stream_.open(filename.c_str(), ios_base::in | ios_base::out | ios_base::trunc);
          }
          

          如果这是您需要的模式。

          没有什么神奇的方法可以打开一个文件进行读/写,如果它不存在则创建它,但如果它存在则不截断它(删除它的内容)。您必须分多个步骤来完成。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-02-08
            • 1970-01-01
            • 1970-01-01
            • 2013-03-18
            • 1970-01-01
            相关资源
            最近更新 更多