我尝试读取作为 zip 存档一部分的二进制文件。因此我用 Poco::Zip 打开了 zip 存档。然后我逐块读取二进制文件
struct Header
{
uint64_t tag;
uint32_t payloadLength;
} __attribute__((packed));
std::ifstream inp("my.zip", std::ios::binary);
Poco::Zip::ZipArchive arch(inp);
Poco::Zip::ZipArchive::FileHeaders::const_iterator it = arch.findHeader("file.dat");
if (it != arch.headerEnd()) {
Poco::Zip::ZipInputStream inStream(inp, it ->second);
Header hdr;
inStream.read(reinterpret_cast<char*>(&hdr), sizeof(hdr));
char buffer[hdr.payloadLength];
inStream.read(reinterpret_cast<char*>(buffer), sizeof(hdr.payloadLength));
...
}
从 ZipInputStream 读取时,我得到了垃圾数据。
当我使用时
std::string str((std::istreambuf_iterator<char>(inStream)), std::istreambuf_iterator<char>());
它有效,但我想避免这种解决方案,因为它将整个文件缓冲在一个可能的大缓冲区中。
read()
这里出了什么问题?
有两件事是错误的。
首先,您忽略了一个重要的文档内容:
ZipArchive(
std::istream & in,
ParseCallback & callback
);
从文件或网络流创建 ZipArchive。 注意,构造函数完成后,in 流将处于失败状态
[我的重点]
或者也许你没有意识到它的重要性。这意味着您需要先清除
inp
的失败状态,然后才能对其进行进一步的访问操作,
在你的情况下意味着之前:
Poco::Zip::ZipInputStream inStream(inp, it->second);
第二,这个:
inStream.read(reinterpret_cast<char*>(buffer), sizeof(hdr.payloadLength));
请求
inStream
将 4 个字节的数据读入 buffer
,因为 sizeof(hdr.payloadLength)
== sizeof(unint32_t)
== 4。你的意思是
读取 hdr.payloadLength
字节数据。 hdr.payloadLength
- buffer
中会有 4 个字节的尾随垃圾。
您可能还注意到:
char buffer[hdr.payloadLength];
是一个变长数组,这在标准 C++ 中是非法的。你会被警告这一点 与
pedantic
。在 C++ 中,您应该使用 std::vector
来表示 VLA。
您更有可能阅读存档的
file.dat
,代码如下:
#include <fstream>
#include <vector>
#include <Poco/Zip/ZipArchive.h>
#include <Poco/Zip/ZipStream.h>
struct Header
{
uint64_t tag;
uint32_t payloadLength;
} __attribute__((packed));
int main()
{
std::ifstream inp("my.zip", std::ios::binary);
Poco::Zip::ZipArchive arch(inp);
Poco::Zip::ZipArchive::FileHeaders::const_iterator it = arch.findHeader("file.dat");
if (it != arch.headerEnd()) {
inp.clear();
Poco::Zip::ZipInputStream inStream(inp, it->second);
Header hdr;
inStream.read(reinterpret_cast<char*>(&hdr), sizeof(hdr));
std::vector<char>::size_type datlen = hdr.payloadLength;
std::vector<char> buffer(datlen);
inStream.read(buffer.data(), datlen);
// ...
}
return 0;
}
虽然你发布的代码不完整,我不知道如何
file.dat
已写,我不能确定。