运行此代码:
#include <stdio.h> // printf
#include <zstd.h> // presumes zstd library is installed
void compress()
{
char buffer[256];
ZSTD_inBuffer in;
ZSTD_outBuffer out;
ZSTD_CCtx *cctx;
in.src = ∈
in.size = 0;
in.pos = 0;
out.dst = buffer;
out.size = sizeof(buffer);
out.pos = 0;
cctx = ZSTD_createCCtx();
ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_flush);
printf("ZSTD_e_flush, total output size: %zd\n", out.pos);
ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_flush);
printf("ZSTD_e_flush, total output size: %zd\n", out.pos);
ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end);
printf("ZSTD_e_end, total output size: %zd\n", out.pos);
ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end);
printf("ZSTD_e_end, total output size: %zd\n", out.pos);
ZSTD_freeCCtx(cctx);
}
int main(int argc, const char** argv)
{
compress();
return 0;
}
输出:
ZSTD_e_flush, total output size: 0
ZSTD_e_flush, total output size: 0
ZSTD_e_end, total output size: 9
ZSTD_e_end, total output size: 18
好像没有生成空块,但是生成了空帧,看起来有点不一致。
如果当前帧没有内容,能不能不生成一个空帧?
如果当前帧没有内容,能不能不生成一个空帧?
正确,无法生成空帧。 想象一下有人连接了 3 个 zstd 帧,而第二个帧为空的情况。 如果第二帧不存在,因为它是空的,我们会将第三个流解释为第二个流,并假设第三个流是空的。 但那是不正确的。
Zstd 总是生成一个有效的帧,它是非空的。
如果需要,您可以在 zstd 之上添加一些代码,将空输入映射到空输出。 但是 zstd 不能这样做。
当指示flush()
没有内容要发送时,流zstd
的当前实现不会生成空块。 因此,它永远不会生成空块。
如果需要此功能,可以更新参考实现以添加它,可能作为流操作的可选参数。
然而,还有另一个问题: zstd
解码器的旧变体有一个错误,使它们无法处理原始空块。 此错误目前已修复,但我们有足够大的用户群,我们不能认为此修复是理所当然的。 因此,为了最大的兼容性,没有zstd
实现应该生成原始空块。
解决方法可能是发送压缩的空块,具有讽刺意味的是,空块大 1 个字节。 如果请求生成空块,该技术将起作用并与所有部署的解码器保持兼容。
无论如何,如果没有足够好的理由(需要支持的重要场景),我们没有动力使参考实现更复杂,因此默认情况下将坚持当前政策不生成空块。
这与空帧不同。
在v1.0
之前,我们确实收到了大量请求,要求能够生成带有NULL
内容的zstd
框架。
从管道的角度来看,这是可以理解的。
通常的流程是input -> zstd compression -> zstd format -> transmit -> assume zstd format -> zstd decompress -> regenerated content
。
输入可以是任何东西,包括空。 简化的管道更喜欢避免特殊情况,因此更喜欢将所有内容发送到zstd
,而没有针对极端情况的特殊分支。
因此,上述管道必须与null
内容兼容,这要求能够生成和解码空帧。
如果问题是:为什么zstd
解码器不会将null
输入解压缩为null
输出生成,
那么回答起来就更复杂了,但是有很多原因我们希望将错误情况和信号缺失与有效传输或空内容的存储区分开来。 在各种流量分析约束之上。 并且让null
输入一个有效的减压条目会混淆这些目标。
非常感谢您的解释。
如果需要,您可以在 zstd 之上添加一些代码,将空输入映射到空输出。
好的,对于有这种需求的人来说,这段代码实现起来并不难。