diff --git a/include/Netra.hpp b/include/Netra.hpp index 997ccbd..85aba11 100644 --- a/include/Netra.hpp +++ b/include/Netra.hpp @@ -120,19 +120,6 @@ namespace QCL */ 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 覆盖写二进制文件(线程安全) * @param data 要写入的二进制数据 @@ -155,7 +142,59 @@ namespace QCL * @param includePattern true 表示返回值包含 pattern 自身长度,false 表示不包含 * @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: std::string filePath_; ///< 文件路径 @@ -302,8 +341,9 @@ namespace QCL // 去除字符串左右两侧的空格 std::string LRtrim(const std::string &s); - - // 通用类型转字符串 + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // c++进行格式化输出 + // 通用类型转字符串 template std::string to_string_any(const T &value) { @@ -366,5 +406,6 @@ namespace QCL return oss.str(); } + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// } diff --git a/src/Netra.cpp b/src/Netra.cpp index 38236e8..bd49921 100644 --- a/src/Netra.cpp +++ b/src/Netra.cpp @@ -231,30 +231,6 @@ namespace QCL return writeToFile(content, std::ios::out | std::ios::app); } - /** - * @brief 按位置写入(线程安全) - */ - bool WriteFile::writeOriginal(const std::string &content, std::streampos position) - { - std::lock_guard 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 覆盖写二进制(线程安全) */ @@ -299,7 +275,7 @@ namespace QCL 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 lock(writeMutex_); @@ -310,9 +286,6 @@ namespace QCL if (!file.is_open()) return 0; - file.clear(); // 清除EOF和错误状态 - file.seekg(0, std::ios::beg); // 回到文件开头 - const size_t chunkSize = 4096; std::string buffer; buffer.reserve(chunkSize * 2); @@ -322,21 +295,148 @@ namespace QCL 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); 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()) 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 lock(writeMutex_); + + // 读取整个文件 + std::ifstream in(filePath_, std::ios::binary); + if (!in.is_open()) + return false; + + std::string fileData((std::istreambuf_iterator(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 lock(writeMutex_); + + // 打开文件读取 + std::ifstream in(filePath_, std::ios::binary); + if (!in.is_open()) + return false; + + std::string fileData((std::istreambuf_iterator(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 lock(writeMutex_); + + // 打开文件读取 + std::ifstream in(filePath_, std::ios::binary); + if (!in.is_open()) + return false; + + std::string fileData((std::istreambuf_iterator(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)); } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// } \ No newline at end of file