使用Boost Zstd过滤流读取压缩日志文件新增内容遇问题
Boost Zstd过滤流无法实时读取新增压缩日志内容的解决方案
我正在开发C++程序,用Boost 1.83的Zstd过滤流追踪磁盘上的实时Zstd压缩日志,但过滤流无法识别文件新增内容。代码如下:
#include <iostream> #include <string> #include <boost/iostreams/filtering_streambuf.hpp> #include <boost/iostreams/filter/zlib.hpp> // Example filter (can be replaced with any filter) #include <fstream> #include <zstd.h> namespace io = boost::iostreams; int main() { // Create a filtering_istreambuf with a zlib decompressor io::filtering_streambuf<io::input> in; in.push(io::zstd_decompressor()); std::ifstream file("compressed_file.txt.zst", std::ios_base::in | std::ios_base::binary); in.push(file); // Construct an istream from the underlying streambuf std::istream inputStream(&in); // Read lines from the input stream using std::getline() while (true) { std::string line; while (std::getline(inputStream, line)) { std::cout << "Line: " << line << std::endl; } if (inputStream.eof()) { inputStream.clear(); } } return 0; }
问题根源
std::ifstream不会主动检测文件长度变化,读到EOF后即使文件新增内容,也不会自动触发重新读取。- Boost过滤流存在内部缓冲,文件新增内容可能被缓冲机制屏蔽,无法被上层流感知。
- 如果日志不是以Zstd多帧格式追加,解压流无法识别后续非完整帧的压缩数据。
解决方案
方案1:定期检查文件变化并重置流
通过定期检查文件大小,判断是否有新增内容,然后重置文件流和过滤流状态,实现实时读取:
#include <iostream> #include <string> #include <boost/iostreams/filtering_streambuf.hpp> #include <boost/iostreams/filter/zstd.hpp> #include <fstream> #include <chrono> #include <thread> namespace io = boost::iostreams; int main() { std::ifstream file("compressed_file.txt.zst", std::ios_base::in | std::ios_base::binary); if (!file.is_open()) { std::cerr << "Failed to open file" << std::endl; return 1; } io::filtering_streambuf<io::input> in; in.push(io::zstd_decompressor()); in.push(file); std::istream inputStream(&in); std::streampos last_pos = file.tellg(); while (true) { // 检查文件是否有新增内容 file.seekg(0, std::ios::end); std::streampos current_size = file.tellg(); if (current_size > last_pos) { // 回到上次读取的位置 file.seekg(last_pos); // 重置过滤流,清除之前的EOF状态和缓冲 in.pop(); in.push(file); inputStream.clear(); // 读取新增内容 std::string line; while (std::getline(inputStream, line)) { std::cout << "Line: " << line << std::endl; } last_pos = file.tellg(); } // 每秒检查一次,可根据需求调整间隔 std::this_thread::sleep_for(std::chrono::seconds(1)); } return 0; }
方案2:禁用过滤流内部缓冲
关闭Boost过滤流的缓冲机制,让数据直接从文件流读取,减少缓冲带来的延迟:
修改过滤流初始化部分:
io::filtering_streambuf<io::input> in; // 禁用过滤流和文件流的缓冲 in.push(io::zstd_decompressor(), io::no_buffer); in.push(file, io::no_buffer); std::istream inputStream(&in);
注意:禁用缓冲会降低读取性能,适合实时性优先的场景。
方案3:确保日志以Zstd多帧格式追加
如果日志写入端是单帧压缩后直接追加,解压流无法识别后续非完整帧数据。需要让写入端每次追加新的Zstd帧:
写入端核心逻辑示例:
#include <fstream> #include <zstd.h> void append_log_to_zstd(const std::string& log_content, const std::string& file_path) { std::ofstream file(file_path, std::ios_base::out | std::ios_base::binary | std::ios_base::app); if (!file.is_open()) return; ZSTD_CCtx* cctx = ZSTD_createCCtx(); if (!cctx) return; // 压缩日志内容为独立Zstd帧 ZSTD_inBuffer in_buf = {log_content.data(), log_content.size(), 0}; ZSTD_outBuffer out_buf; char out_buffer[ZSTD_CStreamOutSize()]; while (in_buf.pos < in_buf.size) { out_buf = {out_buffer, sizeof(out_buffer), 0}; size_t ret = ZSTD_compressStream(cctx, &out_buf, &in_buf); if (ZSTD_isError(ret)) break; file.write(out_buffer, out_buf.pos); } // 结束当前帧 ZSTD_outBuffer end_buf = {out_buffer, sizeof(out_buffer), 0}; size_t ret = ZSTD_endStream(cctx, &end_buf); if (!ZSTD_isError(ret)) { file.write(out_buffer, end_buf.pos); } ZSTD_freeCCtx(cctx); }
内容的提问来源于stack exchange,提问作者Selvaram G
相关产品推荐
相关产品推荐

