我正在使用ZipArchive而我正在编写一个基于zip specification确定zip文件大小的oracle。为简单起见,没有使用压缩。
ZeroFiles
目前我有4个测试,[TestMethod]
public void ZeroFiles()
{
using (var memStream = new MemoryStream())
{
using (var archive = new ZipArchive(memStream, ZipArchiveMode.Create, true)) { }
Assert.AreEqual(ZipSizeOracle(0, 0, 0), memStream.Length);
}
}
正确输出22个字节,并且是适合空zip的大小。
One4ByteFile
[TestMethod]
public void One4ByteFile()
{
using (var memStream = new MemoryStream())
{
using (var archive = new ZipArchive(memStream, ZipArchiveMode.Create, true))
{
var entry1 = archive.CreateEntry("test.txt", CompressionLevel.NoCompression);
using (var writer = new StreamWriter(entry1.Open()))
writer.WriteLine("test");
}
Assert.AreEqual(ZipSizeOracle(1, 8, 4), memStream.Length);
}
}
需要130个字节,但实际值是125个字节
Two4ByteFiles
[TestMethod]
public void Two4ByteFiles()
{
using (var memStream = new MemoryStream())
{
using (var archive = new ZipArchive(memStream, ZipArchiveMode.Create, true))
{
var entry1 = archive.CreateEntry("test.txt", CompressionLevel.NoCompression);
using (var writer = new StreamWriter(entry1.Open()))
writer.WriteLine("test");
var entry2 = archive.CreateEntry("test2.txt", CompressionLevel.NoCompression);
using (var writer = new StreamWriter(entry2.Open()))
writer.WriteLine("test2");
}
Assert.AreEqual(ZipSizeOracle(2, 17, 9), memStream.Length);
}
}
需要241个字节,但实际为231个字节
OneFolder
[TestMethod]
public void OneFolder()
{
using (var memStream = new MemoryStream())
{
using (var archive = new ZipArchive(memStream, ZipArchiveMode.Create, true))
archive.CreateEntry(@"test\", CompressionLevel.NoCompression);
Assert.AreEqual(ZipSizeOracle(1, 4, 0), memStream.Length);
}
}
需要118个字节,但实际值是108个字节
.when('/',{
templateURL:'partials/apply.html',
controller: 'ApplyController'
})
angular.module('myApp').controller('ApplyController',function(){
...
})
为了让oracle给我正确的文件大小,我在规范中缺少什么?
答案 0 :(得分:3)
您缺少以下内容:
数据描述符块是可选的,仅当zip文件以“流式”方式写入时才包含在内(即 - 您事先不知道文件大小并且“动态”写入)。在流式传输时 - 压缩和未压缩数据的大小以及CRC在写入文件头时不可用(因为文件头在数据之前),因此文件头中的所有字节都设置为0,数据描述符块为当此信息可用时,在压缩数据之后包含。如果您提供的示例 - 不包括数据描述符。
NoCompression
中的CreateEntry
级并不意味着字面上包含数据。而是使用deflate算法(您链接的规范中的压缩方法8)处理数据,而不进行实际压缩。即使在“无压缩模式”下,这种deflate算法也增加了自己的开销:
因此,对于输入中的每个数据块(块为2 ^ 16字节),添加了5个字节的开销。在您的示例中,所有文件的大小都小于2 ^ 16,因此只为它们添加了5个字节。
writer.WriteLine
,因此您编写的数据大小在第一个示例中不是4个字节,而是6个,因为添加了\r\n
(换行符)(在第二个示例中为13)。 如果考虑到所有这些(删除12个数据描述符大小,为小文件添加5个大小的deflate开销,传递正确的totalSizeOfFiles
) - 您的示例将产生预期的输出。
有关数据描述符记录的更新。规格说:
这个描述符应该只在不可能的时候使用 在输出.ZIP文件中查找,例如,当输出.ZIP文件时 是标准输出或不可寻找的设备
ZipArchive
类跟随此。如果在构造函数中传递unseekable流 - 它将发出数据描述符记录。例如:
public class UnseekableStream : MemoryStream {
public override bool CanSeek => false;
}
using (var memStream = new UnseekableStream()) {
using (var archive = new ZipArchive(memStream, ZipArchiveMode.Create, true)) {
}
}
这种不可思议的流经常在实践中发生,http响应流就是一个例子。但请注意,12个字节不是数据描述符记录唯一允许的大小:
4.3.9.3 Although not originally assigned a signature, the value 0x08074b50 has commonly been adopted as a signature value for the data descriptor record. Implementers should be aware that ZIP files may be encountered with or without this signature marking data descriptors and SHOULD account for either case when reading ZIP files to ensure compatibility. 4.3.9.4 When writing ZIP files, implementors SHOULD include the signature value marking the data descriptor record. When the signature is used, the fields currently defined for the data descriptor record will immediately follow the signature.
因此,数据描述符可以选择以4字节签名开始,建议实现者在写入时包含该签名,ZipArchive
遵循此建议,因此它发出的数据描述符记录的大小为16字节( 12 + 4签名),而不是12。