如何获取FileStream块的压缩大小(ZipArchive)?

时间:2017-07-20 22:01:33

标签: c# stream zip zlib appx

我正在编写一个小的C#appx包编辑器(appx基本上是一个包含一堆XML元数据文件的zip文件)。

为了制作有效的appx文件,我需要创建一个块映射文件(XML),其中包含每个文件的两个属性:散列和大小,如此处所述(https://docs.microsoft.com/en-us/uwp/schemas/blockmapschema/element-block

Hash表示文件的64kb未压缩块。大小表示压缩后该块的大小(deflate算法)。以下是我到目前为止所写的概念证明:

using System;
using System.IO;
using System.IO.Compression;
using System.Linq;

namespace StreamTest
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var srcFile = File.OpenRead(@"C:\Test\sample.txt"))
            {
                ZipAndHash(srcFile);
            }

        Console.ReadLine();
    }

    static void ZipAndHash(Stream inStream)
    {
        const int blockSize = 65536; //64KB
        var uncompressedBuffer = new byte[blockSize];
        int bytesRead;
        int totalBytesRead = 0;

        //Create a ZIP file
        using (FileStream zipStream = new FileStream(@"C:\Test\test.zip", FileMode.Create))
        {
            using (ZipArchive zipArchive = new ZipArchive(zipStream, ZipArchiveMode.Create))
            {
                using (BinaryWriter zipWriter = new BinaryWriter(zipArchive.CreateEntry("test.txt").Open()))
                {
                    //Read stream with a 64kb buffer
                    while ((bytesRead = inStream.Read(uncompressedBuffer, 0, uncompressedBuffer.Length)) > 0)
                    {
                        totalBytesRead = totalBytesRead + bytesRead;

                        //Compress current block to the Zip entry 
                        if (uncompressedBuffer.Length == bytesRead)
                        {
                            //Hash each 64kb block before compression
                            hashBlock(uncompressedBuffer);

                            //Compress
                            zipWriter.Write(uncompressedBuffer);
                        }
                        else
                        {
                            //Hash remaining bytes and compress
                            hashBlock(uncompressedBuffer.Take(bytesRead).ToArray());
                            zipWriter.Write(uncompressedBuffer.Take(bytesRead).ToArray());
                        }
                    }

                    //How to obtain the size of the compressed block after invoking zipWriter.Write() ?

                    Console.WriteLine($"total bytes : {totalBytesRead}");
                }
            }
        }

    }

    private static void hashBlock(byte[] uncompressedBuffer)
    {
        // hash the block
    }
  }
}

我可以在阅读流时使用64kb缓冲区轻松获取哈希属性,我的问题是:

使用zipWrite.Write()之后如何获取每个64kb块的压缩大小,是否可以使用System.IO.Compression或者我应该使用其他东西?

1 个答案:

答案 0 :(得分:0)

如果您的问题仍然存在,那么对于创建容器,您可以使用2种方法:

  1. 托管OPC打包API ,为生成或使用Open Packaging Conventions兼容文件(称为包)的应用程序提供支持,并自行开发所有特定内容(一般说明如下:{{3} })
  2. 为了即时获取块压缩大小,您可以使用DeflateStream和MemoryStream,如下所示:

    class chararithdemo {
        public static void main(String[] args) {
            char ch ;
            for ( ch = 85; ch = 90; ch++){
               System.out.println( " ch is now : " + ch);
            }
        }
    }    
    
    1. 适用于Appx容器的C ++ API (但在这种情况下,应使用C ++重写Project,或者应编写其他库并将其导入C#项目)。 主要优点是它已经有了创建所有所需包装零件的方法。一般说明在这里(https://msdn.microsoft.com/en-us/library/windows/desktop/dd371623(v=vs.85).aspx
    2. 获取块大小和哈希的解决方案:

      IAppxBlockMapBlock接口提供一个只读对象,该对象表示App包的块映射文件(AppxBlockMap.xml)中包含的文件中的单个块。 IAppxBlockMapFile :: GetBlocks方法用于返回一个枚举器,用于遍历和检索包块映射中列出的文件的各个块。

      IAppxBlockMapBlock接口继承自IUnknown接口并具有以下方法:

      GetCompressedSize - 检索块的压缩大小。

      GetHash - 检索块的哈希值。