.net ZipArchive创建无效的ZIP文件

xoefb8l8  于 2023-11-20  发布在  .NET
关注(0)|答案(7)|浏览(116)

我正在尝试使用带有一个条目的代码创建一个新的ZIP包,并将ZIP包保存到一个文件中。我正在尝试使用System.IO.Compression.ZipArchive类来实现这一点。我正在使用以下代码创建ZIP包:

using (MemoryStream zipStream = new MemoryStream())
{
    using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create))
    {
        var entry = zip.CreateEntry("test.txt");
        using (StreamWriter sw = new StreamWriter(entry.Open()))
        {
            sw.WriteLine(
                "Etiam eros nunc, hendrerit nec malesuada vitae, pretium at ligula.");
        }

字符串
然后我保存ZIP到WinRT中的一个文件:

var file = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync("test.zip", CreationCollisionOption.ReplaceExisting);
        zipStream.Position = 0;
        using (Stream s = await file.OpenStreamForWriteAsync())
        {
            zipStream.CopyTo(s);
        }


或者在正常的.NET 4.5中:

using (FileStream fs = new FileStream(@"C:\Temp\test.zip", FileMode.Create))
        {
            zipStream.Position = 0;
            zipStream.CopyTo(fs);
        }


然而,我无法在Windows资源管理器,WinRAR等中打开生成的文件(我检查了生成的文件的大小与zipStream的长度匹配,因此流本身被正确保存到文件中。
是我做错了什么,还是ZipArchive类有问题?

qrjkbowd

qrjkbowd1#

在我的例子中,问题是当zip文件任务完成时,我没有处理**“zipArchive”**。即使我刷新并关闭了所有流。
所以,要么使用 * 使用 *,如上面的答案所建议的

using (var zipArchive = new ZipArchive(File.OpenWrite("archive.zip"), 
ZipArchiveMode.Create))

字符串
或者在任务结束时处置变量.

zipArchive.Dispose();

vjrehmav

vjrehmav2#

你可以遵循同样的想法,只是在相反的顺序,使用文件流像源.我做了下面的表格和文件被正常打开:

string fileFormat = ".zip"; // any format
string filename = "teste" + fileformat;

StorageFile zipFile = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync(filename,CreationCollisionOption.ReplaceExisting);

using (Stream zipStream = await zipFile.OpenStreamForWriteAsync()){

   using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create)){
        //Include your content here
   }
}

字符串

cgfeq70w

cgfeq70w3#

完整的代码看起来像这样:

var file = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync("test.zip",CreationCollisionOption.ReplaceExisting);
using (Stream zipStream = await zipFile.OpenStreamForWriteAsync())
{
    using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
    {
        var entry = zip.CreateEntry("test.txt");
        using (StreamWriter sw = new StreamWriter(entry.Open()))
        {
            sw.WriteLine("Etiam eros nunc, hendrerit nec malesuada vitae, pretium at ligula.");
        }
    }   
}

字符串

j1dl9f46

j1dl9f464#

如果使用不带花括号的指令,请注意(C# >8.0):

static byte[] CompressAsZip(string fileName, Stream fileStram)
{
    using var memoryStream = new MemoryStream();
    using var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, false);
    using var entryStream = archive.CreateEntry(fileName).Open();

    fileStram.CopyTo(entryStream);

    archive.Dispose(); //<- Necessary to close the archive correctly
    return memoryStream.ToArray();
}

字符串
使用带大括号的using语句,archive.Dispose将在作用域的末尾隐式调用。此外,由于您使用的是C# >8.0,我建议使用这种类型的异步实现,能够归档多个文件并被取消:

static async Task<byte[]> CompressAsZipAsync(
    IAsyncEnumerable<(string FileName, Stream FileStream)> files,
    bool disposeStreamsAfterCompression = false,
    CancellationToken cancellationToken = default)
{
    using var memoryStream = new MemoryStream();
    using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, false))
    {
        await foreach (var (FileName, FileStream) in files.WithCancellation(cancellationToken))
        {
            using var entryStream = archive.CreateEntry(FileName).Open();
            await FileStream.CopyToAsync(entryStream, cancellationToken);

            if (disposeStreamsAfterCompression)
                await FileStream.DisposeAsync();
        }
    }
    return memoryStream.ToArray();
}

3htmauhk

3htmauhk5#

我在代码中发现了一个--事后看来,很明显--错误。ZipArchive必须被处理才能将其内容写入其底层流。因此,我必须在ZipArchive的using块结束后将流保存到一个文件中。
并且,将其构造函数的leaveOpen参数设置为true很重要,以使其不会关闭底层流。因此,这里是完整的工作解决方案:

using (MemoryStream zipStream = new MemoryStream())
{
    using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
    {
        var entry = zip.CreateEntry("test.txt");
        using (StreamWriter sw = new StreamWriter(entry.Open()))
        {
            sw.WriteLine(
                "Etiam eros nunc, hendrerit nec malesuada vitae, pretium at ligula.");
        }
    }

    var file = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync(
        "test.zip",
        CreationCollisionOption.ReplaceExisting);

    zipStream.Position = 0;
    using (Stream s = await file.OpenStreamForWriteAsync())
    {
        zipStream.CopyTo(s);
    }
}

字符串

uurity8g

uurity8g6#

// Create file "archive.zip" in current directory use it as destination for ZIP archive
using (var zipArchive = new ZipArchive(File.OpenWrite("archive.zip"), 
ZipArchiveMode.Create))
{
    // Create entry inside ZIP archive with name "test.txt"
    using (var entry = zipArchive.CreateEntry("test.txt").Open())
    {
        // Copy content from current directory file "test.txt" into created ZIP entry 
        using (var file = File.OpenRead("test.txt"))
        {
            file.CopyTo(entry);
        }
    }
}

字符串
结果,您将获得存档“archive.zip“,其中包含单个条目文件“test.txt”。您需要此using级联,以避免与已处理的资源进行任何交互。

nfg76nw0

nfg76nw07#

在所有的流对象上,你必须从开始处倒回流,以便其他应用程序使用.Seek方法正确地读取它们。
范例:

zipStream.Seek(0, SeekOrigin.Begin);

字符串

相关问题