Fstream无法创建新文件

6
我正在使用一个文件管理器来进行项目开发,以便读取和写入更加方便。如果我没有花费所有的时间来调试,这会非常有用。然而,这个舒适级别实际上给我带来了压力和时间上的浪费。很棒。
问题似乎出在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时,我可以很好地创建文件,但我想将流保持在读/写状态。
我该如何实现这一点?
6个回答

7

最佳方法:

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);
}

因此,代码检测文件是否存在,如果不存在,则创建它。

4

你必须使用显式的openmode参数调用fstream::open函数

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

否则,由于ENOENTopen将失败。
草案C++标准的表95列出了可能的文件打开模式及其在stdio中的等效方式。默认值ios_base::out | ios_base::in等同于r+。我上面列出的等同于w+ios_base::out | ios_base::app等同于a。涉及ios_base::app的所有其他组合都是无效的。
(冒着被嘲笑的风险:您可以切换到stdio并使用文件模式a+,该模式从开头读取并在末尾追加。)

自C++11以来,仅使用ios_base::app是允许的,并且等同于"a"。请参阅C++11或C++14中的表132以获取更新后的表格。 - M.M

3
您不能在不存在的文件上使用std::ios::in。请使用:
std::ios::in | std::ios::out | std::ios::trunc

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


3
我该如何实现这个目标?
std::ofstream file("file.txt");
file << data;

这不是更简单吗?

我承认我不明白这个 FileManager 类的意义,但是原帖作者想要一个读/写流。 - Fred Foo

2
这是库的工作方式:std::ios::in | std::ios::out 相当于 stdio"r+",它只会打开已经存在的文件。我不认为有一种模式可以实现你想要的功能,你需要使用操作系统特定的调用或检查文件是否存在(再次使用操作系统特定的调用),并根据文件是否存在以一种模式或另一种模式打开它。 编辑:我假设您不希望在文件已经存在时将其截断。正如其他人所指出的那样,如果您愿意截断任何现有文件,则可以使用 in | out | trunc

1

只需让您的函数打开

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);
}

如果这是您需要的模式。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接