我正在使用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::openmode
为std::ios::in | std::ios::out
。当我只标记std::ios::out
时,我可以很好地创建文件,但我希望将流保持在读/写状态。
我该如何做到这一点?
答案 0 :(得分: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);
}
因此代码测试现有文件,如果没有,则创建它。
答案 1 :(得分:3)
您不能在不存在的文件上使用std::ios::in
。使用
std::ios::in | std::ios::out | std::ios::trunc
代替(但要确保它不存在或者它将被截断为零字节)。
答案 2 :(得分:3)
您必须使用
的明确fstream::open
参数调用openmode
ios_base::in | ios_base::out | ios_base::trunc
否则open
会因ENOENT
而失败。
C ++标准草案的表95列出了stdio
中可能的文件打开模式及其等价物。默认值ios_base::out | ios_base::in
为r+
。我上面列出的那个相当于w+
。 ios_base::out | ios_base::app
相当于a
。涉及ios_base::app
的所有其他组合均无效。
(冒着被嘲笑的风险:你可以切换到stdio
并使用文件模式a+
,它从头开始读取并在末尾追加。)
答案 3 :(得分:3)
我该如何做到这一点?
std::ofstream file("file.txt");
file << data;
这不是更简单吗?
答案 4 :(得分:2)
这就是图书馆工作的方式:std::ios::in | std::ios::out
以相当于stdio
的{{1}}打开它,也就是说它只会打开现有文件。我不相信有一种模式会做你想要的,你将需要我们一个特定于操作系统的调用或检查文件是否存在(再次,使用特定于操作系统的调用)并以一种模式打开它或另一个取决于它是否已经存在。
编辑:我认为如果文件已经存在,您不希望文件被截断。正如其他人所说,如果你很乐意截断任何现有文件,那么"r+"
是一个选项。
答案 5 :(得分: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);
}
如果这是您需要的模式。
没有神奇的方法可以打开文件进行读/写创建,如果它不存在但不截断它(删除它的内容),如果有的话。你必须分多步完成。