源码
void logfile(std::string fileName, std::string& msg)
{
// 打开文件(如果尚未打开)
if (!logFile.is_open()) {
logFile.open(fileName, std::ios::app);
if (!logFile.is_open())
{
std::cout << "Error: Unable to open log file." << std::endl;
return;
}
// 注册退出时的回调函数
std::atexit(cleanup);
}
std::replace(msg.begin(), msg.end(), '\r', ' ');
// 写入日志
logFile << msg << std::endl;
// 强制刷新缓冲区,确保内容写入磁盘
logFile.flush();
}
问题描述
当我测试这个函数时,一直报错无法打开文件。
思路
1. 最开始以为是权限问题,路径在E:\\Log盘,检查后并没有问题;
2. 然后加上了详细的输出代码:
void logfile(std::string fileName, std::string& msg)
{
// 打开文件(如果尚未打开)
if (!logFile.is_open()) {
logFile.open(fileName, std::ios::app);
if (!logFile.is_open())
{
std::cout << "Error: Unable to open log file." << std::endl;
std::ios_base::iostate state = logFile.rdstate();
if (state & std::ios_base::eofbit)
std::cerr << "End of file reached. ";
if (state & std::ios_base::failbit)
std::cerr << "Non-fatal I/O error occurred. ";
if (state & std::ios_base::badbit)
std::cerr << "Fatal I/O error occurred. ";
if (state & std::ios_base::goodbit)
std::cerr << "No errors. ";
std::cerr << std::endl;
// 清除错误状态
logFile.clear();
return;
}
// 注册退出时的回调函数
std::atexit(cleanup);
}
std::replace(msg.begin(), msg.end(), '\r', ' ');
// 写入日志
logFile << msg << std::endl;
// 强制刷新缓冲区,确保内容写入磁盘
logFile.flush();
}
再次测试控制台打印:Fatal I/O error occurred.经过查询是致命的输入/输出错误,搜索后发现是路径不存在、文件被其他程序占用、程序没有足够权限读写。检查后发现E盘下没有Log文件夹,找到问题原因。
原因
std::ios::app 会将数据追加到文件上,每次并不清空文件的内容。若文件不存在则创建文件,但是并不会创建路径。
解决办法
1. 最简单的手动在E盘创建一个Log文件夹;
2. 修改代码,判断路径是否存在,如果不存在则创建。下面的代码只包含Windows平台和Linux平台。
void ZLogManager::ensureDirectoryExists(const std::string& path)
{
struct stat file_stat;
if (stat(path.c_str(), &file_stat) != 0) {
#ifdef _WIN32
if (_mkdir(path.c_str()) != 0) {
std::cout << "无法创建目录:" << path << std::endl;
return;
}
#else
if (mkdir(path.c_str(), 0777) != 0) {
std::cout << "无法创建目录:" << path << std::endl;
return;
}
#endif
std::cout << "目录:" << path << "创建成功" << std::endl;
}
}
void logfile(std::string fileName, std::string& msg)
{
size_t last_delimiter = fileName.find_last_of("/\\");
if (last_delimiter == std::string::npos) {
std::cout << "非法路径:" << fileName << std::endl;
return;
}
std::string directory_path = fileName.substr(0, last_delimiter);
ZLogManager::ensureDirectoryExists(directory_path);
// 打开文件(如果尚未打开)
if (!logFile.is_open()) {
logFile.open(fileName, std::ios::app);
if (!logFile.is_open())
{
std::cout << "Error: Unable to open log file." << std::endl;
return;
}
// 注册退出时的回调函数
std::atexit(cleanup);
}
std::replace(msg.begin(), msg.end(), '\r', ' ');
// 写入日志
logFile << msg << std::endl;
// 强制刷新缓冲区,确保内容写入磁盘
logFile.flush();
}