0

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

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

哈希表示文件的 64kb 未压缩块。大小表示压缩后该块的大小(放气算法)。这是我写的概念证明:

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 或者我应该使用其他东西?

4

1 回答 1

0

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

  1. 托管的 OPC 打包 API,它为生成或使用符合开放打包约定的文件(称为包)的应用程序提供支持,并自行开发所有特定的东西(一般描述在这里:https ://msdn.microsoft.com/en-us/库/windows/desktop/dd371623(v=vs.85).aspx )

要即时获取块压缩大小,您可以使用 DeflateStream 和 MemoryStream ,如下所示:

      private static long getCompressSize(byte[] input)
    {

        long length = 0;

        using (MemoryStream compressedStream = new MemoryStream())
        {
            compressedStream.Position = 0;

            using (DeflateStream compressionStream = new DeflateStream(compressedStream, CompressionLevel.Optimal, true))
            {
                compressionStream.Write(input, 0, input.Length);

            }


            length = compressedStream.Length;

        }
        Logger.WriteLine("input length:" + input.Length + " compressed stream: " + length);
        return length;
    }
  1. Appx 容器的 C++ API(但在这种情况下,应使用 C++ 重写项目,或者应编写附加库并将其导入 C# 项目)。主要优点是它已经有了创建所有需要的包部分的方法。一般描述在这里(https://msdn.microsoft.com/en-us/library/windows/desktop/hh446766(v=vs.85).aspx

获取块大小和哈希的解决方案:

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

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

GetCompressedSize - 检索块的压缩大小。

GetHash - 检索块的哈希值。

于 2018-02-20T08:10:14.230 回答