总的来说,这是一个非常优秀、健壮且线程安全的文件操作类设计。 成功地应用了 C++ 的核心特性(如继承、多态、RAII、std::mutex等)来解决实际问题。
下面我将进行一个全面的回顾,并提出一些非常细微的建议,这些建议更多是关于代码风格和潜在的边缘情况处理。
代码亮点(总结)
设计模式:正确使用了 ** 接口类(FileBase)和实现类(TextFile)** 的设计模式,通过纯虚函数定义了清晰的契约。
线程安全:TextFile 类内部使用了 std::mutex 和 std::lock_guard 来保护所有对共享资源(file_stream_, is_open_)的访问,实现了线程安全。
资源管理:严格遵守RAII原则。
析构函数会自动调用 Close(),确保文件被关闭,资源被释放。
Open() 和 Close() 方法正确地管理了 file_stream_ 和 is_open_ 的状态。
错误处理:Write 和 WriteLine 方法通过检查 file_stream_.fail() 来判断操作是否成功,并返回 bool 值,让调用者可以处理失败情况。
封装性:
FileBase 中的 filename_ 为 protected,允许子类访问,同时防止外部直接修改。
TextFile 的成员变量 mutex_, file_stream_, is_open_ 均为 private,保证了类的内部状态不会被外部随意篡改。
虚析构函数:FileBase 正确地声明了 virtual ~FileBase() = default;,确保了通过基类指针删除子类对象时的行为是正确的。
cpp
#include <string>
#include <ios>
class FileBase
{
public:
FileBase() = default;
virtual ~FileBase() = default;
virtual bool Open(const std::string &fileName, std::ios_base::openmode mode) = 0;
virtual void Close() = 0;
virtual void Flush() = 0;
virtual bool IsOpen() const = 0;
virtual bool Write(const std::string & data) = 0;
virtual bool WriteLine(const std::string & line) = 0;
virtual std::string Read() = 0;
virtual std::string ReadLine() = 0;
protected:
std::string filename_;
};
cpp
#include <fstream>
#include <mutex>
#include "file_base.hpp"
class TextFile :public FileBase
{
private:
mutable std::mutex mutex_;
std::fstream file_stream_;
bool is_open_;
public:
TextFile();
~TextFile();
bool Open(const std::string &fileName,
std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) override;
void Close() override;
void Flush() override;
bool IsOpen() const override;
bool Write(const std::string & data) override;
bool WriteLine(const std::string & line)override;
std::string Read() override;
std::string ReadLine() override;
};
cpp
#include "file_text.hpp"
#include <sstream>
TextFile::TextFile():file_stream_(),is_open_(false)
{
}
TextFile::~TextFile()
{
Close();
}
bool TextFile::Open(const std::string &fileName,std::ios_base::openmode mode) {
std::lock_guard<std::mutex> lock(mutex_);
//如果TextFile对象已经打开一个文件,再次调用open会失败,fstream对象不能同时打开多个文件
//如果已打开其他文件,先关闭
if(is_open_){
file_stream_.close();
}
file_stream_.open(fileName, mode);
is_open_ = file_stream_.is_open();
if(is_open_){
filename_ = fileName;
}
return is_open_;
}
void TextFile::Close(){
std::lock_guard<std::mutex> lock(mutex_);
if(is_open_){
file_stream_.close();
is_open_ = false;
}
}
void TextFile::Flush(){
std::lock_guard<std::mutex> lock(mutex_);
if(is_open_)
file_stream_.flush();//文件未打开,调用flush不会崩溃,但也是一个无意义的操作
}
bool TextFile::IsOpen() const{
//这里要加锁,防止另一个线程正在写,这时候读会产生未定义行为
std::lock_guard<std::mutex> lock(mutex_);
return is_open_;
}
bool TextFile::Write(const std::string& data){
std::lock_guard<std::mutex> lock(mutex_);
if(!is_open_) return false;
file_stream_ << data; //如果磁盘已满,写入会失败
return !file_stream_.fail();
}
bool TextFile::WriteLine(const std::string & line){
std::lock_guard<std::mutex> lock(mutex_);
if(!is_open_) return false;
file_stream_ << line << '\n';
return !file_stream_.fail();
}
std::string TextFile::Read(){
std::lock_guard<std::mutex> lock(mutex_);
if(!is_open_) return "";
std::ostringstream ss;
ss << file_stream_.rdbuf();
return ss.str();
}
std::string TextFile::ReadLine(){
std::lock_guard<std::mutex> lock(mutex_);
if(!is_open_) return "";
std::string line;
if(getline(file_stream_,line)){
return line;
}else{
return "";
}
}