简体   繁体   English

Package (.zip) 字节数组文件 .net 内核

[英]Package (.zip) a byte array file .net core

I tried following this SO: Create zip file from byte[] as a dummy project and it looks like this:我尝试遵循这个 SO: Create zip file from byte[]作为一个虚拟项目,它看起来像这样:

using System.IO.Compression;
using System.IO;
using System.Net.Http;
using System;

namespace TestApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            using var compressedFileStream = new MemoryStream();
            using var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Create);

            //Create a zip entry for each attachment
            var zipEntry = zipArchive.CreateEntry("test.txt");
            var file = File.ReadAllBytes("test.txt");

            //Get the stream of the attachment
            using var originalFileStream = new MemoryStream(file);
            using var zipEntryStream = zipEntry.Open();
            //Copy the attachment stream to the zip entry stream
            originalFileStream.CopyTo(zipEntryStream);

            var toarraybaby = compressedFileStream.ToArray();

            File.WriteAllBytes("hehe.zip", toarraybaby);
        }
    }
}

I get a.zip file as output and the file has a size.我得到一个 .zip 文件作为 output 并且该文件有一个大小。 But when trying to open the file I get that its corrupt.但是当试图打开文件时,我发现它已损坏。 What am I missing?我错过了什么?

What's wrong with that code specifically is that a C# 8-style using declaration disposes the at end of the current scope.该代码的具体问题在于 C# 8 样式using声明处理了当前 scope 的末尾。 That's too late.为时已晚。 The zip archive has to be disposed to ensure it writes all the necessary data to its output stream, but by the time it does that, Main has ended.必须处理 zip 存档,以确保将所有必要的数据写入其 output stream,但到那时, Main已经结束。

There are various ways to ensure it gets disposed earlier, for example:有多种方法可以确保提前处理它,例如:

using var compressedFileStream = new MemoryStream();
// using an old-style using statement here to ensure the zip archive gets disposed early enough
using (var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Create))
{
    //Create a zip entry for each attachment
    var zipEntry = zipArchive.CreateEntry("test.txt");
    var file = File.ReadAllBytes("test.txt");

    //Get the stream of the attachment
    using var originalFileStream = new MemoryStream(file);
    using var zipEntryStream = zipEntry.Open();
    //Copy the attachment stream to the zip entry stream
    originalFileStream.CopyTo(zipEntryStream);

}
var toarraybaby = compressedFileStream.ToArray();

File.WriteAllBytes("hehe.zip", toarraybaby);

The problem is that you are not flushing the Zip into the MemoryStream until it gets closed at the end of the function.问题是您没有将 Zip 刷新到MemoryStream中,直到它在 function 结束时关闭。 You could manually put in a Flush or close the using at the right place.您可以手动放入Flush或在正确的位置关闭using

But ideally you would not use a MemoryStream at all.但理想情况下,您根本不会使用MemoryStream Instead, just feed the zip straight into a FileStream .相反,只需将 zip 直接输入FileStream即可。 Also you should use async if possible.如果可能的话,你也应该使用async

static async Task Main(string[] args)
{
    using var compressedFileStream = new FileStream("hehe.zip", FileMode.Create, FileAccess.ReadWrite, FileShare.None, 4096, true);
    using var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Create);

    //Create a zip entry for each attachment
    var zipEntry = zipArchive.CreateEntry("test.txt");
    using var originalFileStream = new FileStream("test.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.None, 4096, true);

    //Get the stream of the attachment
    using var zipEntryStream = zipEntry.Open();

    //Copy the attachment stream to the zip entry stream
    await originalFileStream.CopyToAsync(zipEntryStream);
}

I just used the following code and it worked for me:我刚刚使用了以下代码,它对我有用:

var folderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var outputFilePath = Path.Combine(folderPath, "Test.zip");

using var outputFile = File.Create(outputFilePath);
using var archive = new ZipArchive(outputFile, ZipArchiveMode.Create);

var inputFileName = "Test.txt";
var inputFilePath = Path.Combine(folderPath, inputFileName);
var entry = archive.CreateEntry(inputFileName);

using var inputFile = File.OpenRead(inputFilePath);
using var entryStream = entry.Open();

inputFile.CopyTo(entryStream);

I was able to open that ZIP file in File Explorer and then open the text file it contained and see the same original text.我能够在文件资源管理器中打开该 Z4348F938BDDDD8475E967CCB47ECB234Z 文件,然后打开它包含的文本文件并看到相同的原始文本。 If you want to create a new ZIP file containing arbitrary existing files, that's how I'd do it.如果您想创建一个包含任意现有文件的新 ZIP 文件,我就是这样做的。

I then tried replacing the output FileStream with a MemoryStream while making the fewest changes to the code as possible and got this:然后我尝试用MemoryStream替换 output FileStream ,同时对代码进行尽可能少的更改,并得到了这个:

var folderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var outputFilePath = Path.Combine(folderPath, "Test.zip");

using var outputStream = new MemoryStream();
using var archive = new ZipArchive(outputStream, ZipArchiveMode.Create);

var inputFileName = "Test.txt";
var inputFilePath = Path.Combine(folderPath, inputFileName);
var entry = archive.CreateEntry(inputFileName);

using var inputFile = File.OpenRead(inputFilePath);
using var entryStream = entry.Open();

inputFile.CopyTo(entryStream);

var data = outputStream.ToArray();

File.WriteAllBytes(outputFilePath, data);

When I ran that, I ended up with a corrupt ZIP file.当我运行它时,我得到了一个损坏的 ZIP 文件。 I'm not sure what the specific reason is but, if my first code snippet works for you, it's not really worth finding out.我不确定具体原因是什么,但是,如果我的第一个代码片段对你有用,那真的不值得一试。 If you really need to use a MemoryStream , let me know and I'll investigate a bit further.如果您真的需要使用MemoryStream ,请告诉我,我会进一步调查。 It may have to do with the order of disposing objects but I'm not sure.它可能与处理对象的顺序有关,但我不确定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM