从字节(在内存中使用任意编码的文本)在内存中创建zip文件

Dan*_*bio 2 c# compression zip

我正在开发的应用程序需要将xml文件压缩为zip文件,并通过http请求将其发送到Web服务。因为我不需要保留zip文件,所以我只是在内存中执行压缩。Web服务拒绝了我的请求,因为zip文件显然格式错误。

我知道此问题中有一个解决方案可以很好地工作,但它使用了StreamWriter。该解决方案的我的问题是,StreamWriter需要编码或假设UTF-8,并且我不需要知道xml文件的编码。我只需要从这些文件中读取字节,然后将它们存储在zip文件中,无论它们使用哪种编码即可。

因此,很明显,这个问题与编码无关,因为我不需要将字节转换为文本或相反。我只需要压缩一个byte[]

我正在使用下一个代码来测试zip文件的格式是否错误:

static void Main(string[] args)
{
    Encoding encoding = Encoding.GetEncoding("ISO-8859-1");

    string xmlDeclaration = "<?xml version=\"1.0\" encoding=\"" + encoding.WebName.ToUpperInvariant() + "\"?>";
    string xmlBody = "<Test>ª!\"·$%/()=?¿\\|@#~€¬'¡º</Test>";
    string xmlContent = xmlDeclaration + xmlBody;
    byte[] bytes = encoding.GetBytes(xmlContent);
    string fileName = "test.xml";
    string zipPath = @"C:\Users\dgarcia\test.zip";

    Test(bytes, fileName, zipPath);
}

static void Test(byte[] bytes, string fileName, string zipPath)
{
    byte[] zipBytes;

    using (var memoryStream = new MemoryStream())
    using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, leaveOpen: false))
    {
        var zipEntry = zipArchive.CreateEntry(fileName);
        using (Stream entryStream = zipEntry.Open())
        {
            entryStream.Write(bytes, 0, bytes.Length);
        }

        //Edit: as the accepted answer states, the problem is here, because i'm reading from the memoryStream before disposing the zipArchive.
        zipBytes = memoryStream.ToArray();
    }

    using (var fileStream = new FileStream(zipPath, FileMode.OpenOrCreate))
    {
        fileStream.Write(zipBytes, 0, zipBytes.Length);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我尝试打开该文件,则会出现“意外的文件结尾”错误。因此,显然,Web服务正在正确报告格式错误的zip文件。到目前为止我尝试过的是:

  • 冲洗entryStream
  • 关闭entryStream
  • 冲洗和关闭entryStream

请注意,如果我zipArchive直接从fileStreamzip文件中打开,则不会形成任何错误。但是,这fileStream只是一个测试,我需要在内存中创建我的zip文件。

Evk*_*Evk 5

您尝试MemoryStream过早获取字节,还ZipArchive没有全部写入。而是这样做:

using (var memoryStream = new MemoryStream()) {
    // note "leaveOpen" true, to not dispose memoryStream too early
    using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, leaveOpen: true)) {
        var zipEntry = zipArchive.CreateEntry(fileName);
        using (Stream entryStream = zipEntry.Open()) {
            entryStream.Write(bytes, 0, bytes.Length);
        }                    
    }
    // now, after zipArchive is disposed - all is written to memory stream
    zipBytes = memoryStream.ToArray();
}
Run Code Online (Sandbox Code Playgroud)