使用InternetReadFile下载Gzip文件,Boost解压抛出异常求助
问题分析与修复方案
核心问题:二进制数据读取截断
你的代码在读取Gzip二进制数据时,使用了std::string::append(const char*)方法,该方法会将传入的char数组当作C风格字符串处理,遇到第一个\0字节就停止追加。但Gzip压缩数据属于二进制格式,内部必然包含\0字节,这会导致_data只保存了部分不完整的数据,后续Boost解压时因数据损坏抛出异常。
修复步骤
1. 修正数据读取逻辑
将_data.append(tmp)改为带长度的重载版本,确保完整读取所有二进制数据:
while (InternetReadFile(*httpfile, tmp, 2048, &rSize) && rSize > 0) { // 按实际读取长度追加,避免\0截断 _data.append(tmp, rSize); // 注释掉无用的CString操作,它不适合处理二进制数据 // tmp[rSize] = '\0'; // buffer += (CString)tmp; }
2. 可选:验证响应编码
可以在读取数据前,确认服务器返回的确实是Gzip编码,避免不必要的解压操作:
CString contentEncoding; if (httpfile->QueryInfo(HTTP_QUERY_CONTENT_ENCODING, contentEncoding)) { if (contentEncoding.CompareNoCase(_T("gzip")) != 0) { // 非Gzip编码,直接处理原始数据即可 } }
3. 异常捕获与排查
添加异常捕获逻辑,获取Boost抛出的具体错误信息,帮助快速定位问题:
try { boost::iostreams::copy(in, _sstream); } catch (const boost::iostreams::gzip_error& e) { std::cerr << "Gzip解压错误: " << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << "操作错误: " << e.what() << std::endl; }
修复后的完整代码片段
CInternetSession isession; CString url = m_url; std::string _data; CString hdrs = _T("Accept-Encoding: gzip, deflate\r\nUser-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)\r\n"); CHttpFile* httpfile = (CHttpFile*)isession.OpenURL(url, 1, INTERNET_FLAG_SECURE | INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_RELOAD, hdrs, hdrs.GetLength()); if (httpfile) { DWORD dwStatusCode; httpfile->QueryInfoStatusCode(dwStatusCode); if (dwStatusCode == 200) { DWORD rSize; char tmp[2048 + 1]; while (InternetReadFile(*httpfile, tmp, 2048, &rSize) && rSize > 0) { _data.append(tmp, rSize); } } httpfile->Close(); delete httpfile; } using namespace boost::iostreams; try { filtering_streambuf<input> in; in.push(gzip_decompressor()); in.push(boost::iostreams::array_source(_data.data(), _data.size())); std::stringstream _sstream; boost::iostreams::copy(in, _sstream); std::cout << _sstream.rdbuf(); } catch (const boost::iostreams::gzip_error& e) { std::cerr << "Gzip解压失败: " << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << "操作失败: " << e.what() << std::endl; }
内容的提问来源于stack exchange,提问作者Сергей Соколов
相关产品推荐
相关产品推荐

