我为我的一个C++项目创建了一个“File”类,它基于ofstream。这是简化的代码:
文件.h
#include <fstream>
#include <mutex>
#include <filesystem>
#include <vector>
class File
{
private:
std::ofstream writer;
static std::mutex file_mtx;
std::filesystem::path path;
public:
File();
File(const std::filesystem::path &_path);
void write(const std::vector<std::string> &lines);
};
文件.cpp
File::File(const std::filesystem::path &_path) : path(_path)
{
// Create file
std::lock_guard<std::mutex> lock(file_mtx);
writer.open(path, std::ios::app);
writer.close();
}
void File::write(const std::vector<std::string> &lines)
{
std::lock_guard<std::mutex> lock(file_mtx);
writer.open(path, std::ios::app);
if (!writer.is_open())
return;
for (const auto &line : lines)
writer << line
<< "\n";
writer.close();
}
std::mutex File::file_mtx;
我仅在需要提高效率时才使用 ofstream 打开文件,并且使用互斥锁来防止两个不同的对象同时写入同一文件。写入功能也在附加模式下打开(
std::ios::app
)。
这是我的“测试”代码:
#include "file.h"
int main(int argc, char *argv[])
{
File test("./test.txt");
test.write({
"Hello",
"World"
});
File test2("./test.txt");
test2.write({
"Part",
"2"
});
return 0;
}
我对同一个文件有两个不同的变量的原因是因为在我的实际代码中,必须在两个不同的作用域中访问该文件,因此必须定义两个变量。
这是文件的输出:
Part
2
这是预期的输出:
Hello
World
Part,
2
尽管互斥体在函数开始时被锁定,并且尽管文件以追加模式打开,但文件仍然会被覆盖。我想知道为什么会发生这种情况,以及为什么互斥体首先不能阻止文件被覆盖。
这是我的最小可重现示例:
#include <fstream>
#include <mutex>
#include <filesystem>
#include <vector>
class File
{
private:
std::ofstream writer;
std::filesystem::path path;
public:
File(const std::filesystem::path &_path) : path(_path)
{
// Create file
writer.open(path, std::ios::app);
writer.close();
}
void write(const std::vector<std::string> &lines)
{
if (!writer.is_open())
return;
for (const auto &line : lines)
writer << line
<< "\n";
writer.close();
}
};
int main(int argc, char *argv[])
{
File test("./test.txt");
test.write({"Hello",
"World"});
File test2("./test.txt");
test2.write({"Part",
"2"});
return 0;
}
您的问题与互斥体无关。在您最初发布的代码中,该文件在构造函数中重新创建:
File::File(const std::filesystem::path& _path) : path(_path)
{
// Create file
std::lock_guard<std::mutex> lock(file_mtx);
writer.open(path);
writer.close();
}
然后将上面的代码替换为:
File(const std::filesystem::path& _path) : path(_path)
{
// Create file
writer.open(path, std::ios::app);
writer.close();
}
此代码不会重新创建文件,但不会产生预期的结果,因为文件是以追加模式打开的。因此,每次运行程序时,都会附加文本:
Hello
World
Part
2
Hello
World
Part
2...
您可能想要的是
Reset
方法:
File(const std::filesystem::path& _path) : path(_path)
{
// no code here
}
void Reset()
{
// the code you originally placed in constructor
}
int main(int argc, char* argv[])
{
File("./test.txt").Reset();
// ...
}