使用通用流通过 SharpCompress 创建压缩文件

Posted

技术标签:

【中文标题】使用通用流通过 SharpCompress 创建压缩文件【英文标题】:Using a generic stream to create a zipped file with SharpCompress 【发布时间】:2017-06-01 10:44:45 【问题描述】:

由于 System.IO.Compression seems to be out of reach for now 如果我想同时使用 dotnet core + net461,我已经尝试使用 SharpCompress

“读取 zip”部分很简单,但我很难找出如何写入 zip 流。

The wiki of the project 有点过时了。 This is the only example 我发现它适用于写入流。我试图遵循它并使其适应我的需求,但我被它抛出的异常困住了:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.Common;
using SharpCompress.Compressors.Deflate;
using SharpCompress.Writers;
using System;
using System.IO;

namespace DbManager.DjdbCore.Tests

    [TestClass]
    public class ZipTests
    
        public ZipTests()
        
            Directory.SetCurrentDirectory(AppContext.BaseDirectory);
        

        [TestMethod]
        public void Test()
                    
            var zip = File.OpenWrite(@"..\..\..\..\..\test-resources\zip_file_test.zip");
            var writerOptions = new WriterOptions(CompressionType.Deflate);
            var zipWriter = WriterFactory.Open(zip, ArchiveType.Zip, writerOptions);            

            var memoryStream = new MemoryStream();            
            var binaryWriter = new BinaryWriter(memoryStream);
            binaryWriter.Write("Test string inside binary file - text to fill it up: qoiwjqefñlawijfñlaskdjfioqwjefñalskvndñaskvnqo`wiefowainvñaslkfjnwpowiqjfeopwiqjnfjñlaskdjfñlasdfjiowiqjefñaslkdjfñalskjfpqwoiefjqw");

            var deflateStream = new DeflateStream(memoryStream, SharpCompress.Compressors.CompressionMode.Compress);
            deflateStream.Write(memoryStream.ToArray(), 0, Convert.ToInt32(memoryStream.Length));

            // EXCEPTION: SharpCompress.Compressors.Deflate.ZlibException: 'Cannot Read after Writing.'
            // Source code: if (_streamMode != StreamMode.Reader)  throw new ZlibException("Cannot Read after Writing."); 
            zipWriter.Write("test_file_inside_zip.bin", deflateStream, DateTime.Now);                         

            zip.Flush();

            zipWriter.Dispose();
            zip.Dispose();            
        

    

如果有帮助,这就是我使用库 System.IO.Compression 使用的(并且它有效,但仅在 dotnet 核心中):

private void WriteAsZipBinary()

    //Open the zip file if it exists, else create a new one 
    var zip = ZipPackage.Open(this.FileFullPath, FileMode.OpenOrCreate, FileAccess.ReadWrite);

    var zipStream = ZipManager.GetZipWriteStream(zip, nameOfFileInsideZip);

    var memoryStream = new MemoryStream();
    var binaryWriter = new BinaryWriter(memoryStream);

    // Here is where strings etc are written to the binary file:
    WriteStuffInBinaryStream(ref binaryWriter);

    //Read all of the bytes from the file to add to the zip file 
    byte[] bites = new byte[Convert.ToInt32(memoryStream.Length - 1) + 1];
    memoryStream.Position = 0;
    memoryStream.Read(bites, 0, Convert.ToInt32(memoryStream.Length));

    binaryWriter.Dispose();
    binaryWriter = null;

    memoryStream.Dispose();
    memoryStream = null;

    zipStream.Position = 0;
    zipStream.Write(bites, 0, bites.Length);

    zip.Close();

   

public static Stream GetZipWriteStream(Package zip, string renamedFileName)


    //Replace spaces with an underscore (_) 
    string uriFileName = renamedFileName.Replace(" ", "_");

    //A Uri always starts with a forward slash "/" 
    string zipUri = string.Concat("/", Path.GetFileName(uriFileName));

    Uri partUri = new Uri(zipUri, UriKind.Relative);
    string contentType = "Zip"; // System.Net.Mime.MediaTypeNames.Application.Zip;

    //The PackagePart contains the information: 
    // Where to extract the file when it's extracted (partUri) 
    // The type of content stream (MIME type):  (contentType) 
    // The type of compression:  (CompressionOption.Normal)   
    PackagePart pkgPart = zip.CreatePart(partUri, contentType, CompressionOption.Normal);

    //Compress and write the bytes to the zip file 
    return pkgPart.GetStream();


【问题讨论】:

【参考方案1】:

我将在这里发布来自@adamhathcock(项目所有者)的answer on github:

[TestMethod]
public void Test()
            

    var writerOptions = new WriterOptions(CompressionType.Deflate);
    using(var zip = File.OpenWrite(@"..\..\..\..\..\test-resources\zip_file_test.zip"))
    using(var zipWriter = WriterFactory.Open(zip, ArchiveType.Zip, writerOptions))
    
        var memoryStream = new MemoryStream();            
        var binaryWriter = new BinaryWriter(memoryStream);
        binaryWriter.Write("Test string inside binary file - text to fill it up: qoiwjqefñlawijfñlaskdjfioqwjefñalskvndñaskvnqo`wiefowainvñaslkfjnwpowiqjfeopwiqjnfjñlaskdjfñlasdfjiowiqjefñaslkdjfñalskjfpqwoiefjqw");

        memoryStream.Position = 0;
        zipWriter.Write("test_file_inside_zip.bin", memoryStream, DateTime.Now);                          
    

两件事:

    写入后忘记重置 MemoryStream 以便读取。

    您无需手动使用 DeflateStream。您已经告诉 ZipWriter 使用什么压缩。如果它有效,您将双重压缩实际上是垃圾的字节。

【讨论】:

以上是关于使用通用流通过 SharpCompress 创建压缩文件的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 sharpcompress 解压 .xz (lzma2) 文件

SharpCompress & LZMA2 7z 存档 - 特定文件的提取速度非常慢。为啥?备择方案?

使用 SharpCompress 库发布 WinRT 应用程序

实时流计算

实时流计算

实时流计算