Writefile

This commit is contained in:
Quella777
2025-08-16 10:33:24 +08:00
parent 9bfc4c2538
commit c8ce637315
2 changed files with 190 additions and 51 deletions

View File

@@ -120,19 +120,6 @@ namespace QCL
*/ */
bool appendText(const std::string &content); bool appendText(const std::string &content);
/**
* @brief 按指定位置写入文本(原文写,线程安全)
*
* 不清空文件内容,仅替换指定位置的内容。
* 若文件不存在,则会自动创建空文件。
*
* @param content 要写入的内容
* @param position 写入位置(默认为文件开头)
* @return true 写入成功
* @return false 写入失败
*/
bool writeOriginal(const std::string &content, std::streampos position = 0);
/** /**
* @brief 覆盖写二进制文件(线程安全) * @brief 覆盖写二进制文件(线程安全)
* @param data 要写入的二进制数据 * @param data 要写入的二进制数据
@@ -155,7 +142,59 @@ namespace QCL
* @param includePattern true 表示返回值包含 pattern 自身长度false 表示不包含 * @param includePattern true 表示返回值包含 pattern 自身长度false 表示不包含
* @return size_t 字节数,如果文件没打开或 pattern 为空则返回 0 * @return size_t 字节数,如果文件没打开或 pattern 为空则返回 0
*/ */
size_t countBytesBeforePattern(const std::string &pattern, bool includePattern = false); size_t countBytesPattern(const std::string &pattern, bool includePattern = false);
/**
* @brief 在文件中查找指定字节序列并在其后写入内容,如果不存在则追加到文件末尾
* @param pattern 要查找的字节序列
* @param content 要写入的内容
* @return true 写入成功false 文件打开失败
*
* 功能说明:
* 1. 若文件中存在 pattern则删除 pattern 之后的所有内容,并在其后插入 content。
* 2. 若文件中不存在 pattern则在文件末尾追加 content若末尾无换行符则先补充换行。
*/
bool writeAfterPatternOrAppend(const std::string &pattern, const std::string &content);
/**
* @brief 在文件指定位置之后插入内容
* @param content 要插入的内容
* @param pos 插入位置(从文件开头算起的字节偏移量)
* @param length 插入的长度(>= content.size() 时,多余部分用空字节填充;< content.size() 时只截取前 length 个字节)
* @return true 插入成功false 文件打开失败或参数不合法
*
* 功能说明:
* 1. 不会覆盖原有数据,而是将 pos 之后的内容整体向后移动 length 个字节。
* 2. 如果 length > content.size(),则在 content 后补充 '\0'(或空格,可按需求改)。
* 3. 如果 length < content.size(),则只写入 content 的前 length 个字节。
* 4. 文件整体大小会增加 length 个字节。
*
* 举例:
* 原始文件内容: "ABCDEFG"
* insertAfterPos("XY", 2, 3) // 在索引 2 后插入
* 结果: "ABX Y\0CDEFG" (这里 \0 代表补充的空字节)
*/
bool insertAfterPos(const std::string &content, size_t pos, size_t length);
/**
* @brief 在文件指定位置覆盖写入内容
* @param content 要写入的内容
* @param pos 覆盖起始位置(从文件开头算起的字节偏移量)
* @param length 覆盖长度
* @return true 覆盖成功false 文件打开失败或 pos 越界
*
* 功能说明:
* 1. 从 pos 开始覆盖 length 个字节,不会移动或增加文件大小。
* 2. 如果 content.size() >= length则只写入前 length 个字节。
* 3. 如果 content.size() < length则写入 content并用 '\0' 补齐至 length。
* 4. 如果 pos + length 超过文件末尾,则只覆盖到文件尾部,不会越界。
*
* 举例:
* 原始文件内容: "ABCDEFG"
* overwriteAtPos("XY", 2, 3)
* 结果: "ABXYEFG" (原 "CDE" 被 "XY\0" 覆盖,\0 实际不可见)
*/
bool overwriteAtPos(const std::string &content, size_t pos, size_t length);
private: private:
std::string filePath_; ///< 文件路径 std::string filePath_; ///< 文件路径
@@ -302,7 +341,8 @@ namespace QCL
// 去除字符串左右两侧的空格 // 去除字符串左右两侧的空格
std::string LRtrim(const std::string &s); std::string LRtrim(const std::string &s);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// c++进行格式化输出
// 通用类型转字符串 // 通用类型转字符串
template <typename T> template <typename T>
std::string to_string_any(const T &value) std::string to_string_any(const T &value)
@@ -366,5 +406,6 @@ namespace QCL
return oss.str(); return oss.str();
} }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
} }

View File

@@ -231,30 +231,6 @@ namespace QCL
return writeToFile(content, std::ios::out | std::ios::app); return writeToFile(content, std::ios::out | std::ios::app);
} }
/**
* @brief 按位置写入(线程安全)
*/
bool WriteFile::writeOriginal(const std::string &content, std::streampos position)
{
std::lock_guard<std::mutex> lock(writeMutex_);
std::ofstream file(filePath_, std::ios::in | std::ios::out);
if (!file.is_open())
{
// 文件不存在则创建
file.open(filePath_, std::ios::out);
file.close();
file.open(filePath_, std::ios::in | std::ios::out);
}
if (!file.is_open())
return false;
file.seekp(position);
file << content;
file.close();
return true;
}
/** /**
* @brief 覆盖写二进制(线程安全) * @brief 覆盖写二进制(线程安全)
*/ */
@@ -299,7 +275,7 @@ namespace QCL
return true; return true;
} }
size_t WriteFile::countBytesBeforePattern(const std::string &pattern, bool includePattern) size_t WriteFile::countBytesPattern(const std::string &pattern, bool includePattern)
{ {
std::lock_guard<std::mutex> lock(writeMutex_); std::lock_guard<std::mutex> lock(writeMutex_);
@@ -310,9 +286,6 @@ namespace QCL
if (!file.is_open()) if (!file.is_open())
return 0; return 0;
file.clear(); // 清除EOF和错误状态
file.seekg(0, std::ios::beg); // 回到文件开头
const size_t chunkSize = 4096; const size_t chunkSize = 4096;
std::string buffer; std::string buffer;
buffer.reserve(chunkSize * 2); buffer.reserve(chunkSize * 2);
@@ -322,21 +295,148 @@ namespace QCL
while (file.read(chunk, chunkSize) || file.gcount() > 0) while (file.read(chunk, chunkSize) || file.gcount() > 0)
{ {
buffer.append(chunk, file.gcount()); size_t bytesRead = file.gcount();
buffer.append(chunk, bytesRead);
size_t pos = buffer.find(pattern); size_t pos = buffer.find(pattern);
if (pos != std::string::npos) if (pos != std::string::npos)
{ {
return includePattern ? (pos + pattern.size()) : pos; size_t absolutePos = totalRead + pos; // 关键:加上 totalRead
return includePattern ? (absolutePos + pattern.size()) : absolutePos;
} }
// 保留末尾部分,避免 buffer 无限增长
if (buffer.size() > pattern.size()) if (buffer.size() > pattern.size())
buffer.erase(0, buffer.size() - pattern.size()); buffer.erase(0, buffer.size() - pattern.size());
totalRead += file.gcount(); totalRead += bytesRead; // 读完后再累计
} }
return 0; // 没找到 pattern返回0 return 0;
}
bool WriteFile::writeAfterPatternOrAppend(const std::string &pattern, const std::string &content)
{
std::lock_guard<std::mutex> lock(writeMutex_);
// 读取整个文件
std::ifstream in(filePath_, std::ios::binary);
if (!in.is_open())
return false;
std::string fileData((std::istreambuf_iterator<char>(in)), {});
in.close();
size_t pos = fileData.find(pattern);
if (pos != std::string::npos)
{
// 模式存在,插入位置在模式结尾
pos += pattern.size();
// 删除模式后所有内容
if (pos < fileData.size())
fileData.erase(pos);
// 插入新内容
fileData.insert(pos, content);
}
else
{
// 模式不存在,直接追加到文件末尾
if (!fileData.empty() && fileData.back() != '\n')
fileData += '\n'; // 保证换行
fileData += content;
}
// 写回文件
std::ofstream out(filePath_, std::ios::binary | std::ios::trunc);
if (!out.is_open())
return false;
out.write(fileData.data(), fileData.size());
return true;
}
bool WriteFile::overwriteAtPos(const std::string &content, size_t pos, size_t length)
{
std::lock_guard<std::mutex> lock(writeMutex_);
// 打开文件读取
std::ifstream in(filePath_, std::ios::binary);
if (!in.is_open())
return false;
std::string fileData((std::istreambuf_iterator<char>(in)), {});
in.close();
// 边界检查
if (pos >= fileData.size())
return false; // pos 超过文件范围,无法覆盖
// 生成要覆盖的实际数据块
std::string overwriteBlock;
if (content.size() >= length)
{
overwriteBlock = content.substr(0, length);
}
else
{
overwriteBlock = content;
overwriteBlock.append(length - content.size(), '\0'); // 补齐
}
// 计算实际可写范围
size_t maxWritable = std::min(length, fileData.size() - pos);
// 覆盖
fileData.replace(pos, maxWritable, overwriteBlock.substr(0, maxWritable));
// 写回文件
std::ofstream out(filePath_, std::ios::binary | std::ios::trunc);
if (!out.is_open())
return false;
out.write(fileData.data(), fileData.size());
return true;
}
bool WriteFile::insertAfterPos(const std::string &content, size_t pos, size_t length)
{
std::lock_guard<std::mutex> lock(writeMutex_);
// 打开文件读取
std::ifstream in(filePath_, std::ios::binary);
if (!in.is_open())
return false;
std::string fileData((std::istreambuf_iterator<char>(in)), {});
in.close();
// 边界检查
if (pos > fileData.size())
pos = fileData.size(); // 如果 pos 超出范围,就视为文件末尾
// 生成要插入的实际数据块
std::string insertBlock;
if (content.size() >= length)
{
insertBlock = content.substr(0, length); // 只取前 length 个字节
}
else
{
insertBlock = content; // 全部内容
insertBlock.append(length - content.size(), '\0'); // 补足空字节
}
// 插入到 pos 后面
fileData.insert(pos + 1, insertBlock);
// 写回文件
std::ofstream out(filePath_, std::ios::binary | std::ios::trunc);
if (!out.is_open())
return false;
out.write(fileData.data(), fileData.size());
return true;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -547,7 +647,5 @@ namespace QCL
return Ltrim(Rtrim(s)); return Ltrim(Rtrim(s));
} }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
} }