C# 在C中从多个内存中文件创建Zip存档#

C# 在C中从多个内存中文件创建Zip存档#,c#,compression,zip,C#,Compression,Zip,当文件当前在内存中时,是否有方法创建包含多个文件的Zip存档?我想要保存的文件实际上只是文本文件,并且存储在我的应用程序中的字符串类中。但是我想在一个独立的归档中保存多个文件。它们都可以位于归档文件的根目录中 如果能够使用SharpZipLib来实现这一点,那就太好了。是的,您可以使用SharpZipLib来实现这一点-当您需要提供要写入的流时,使用内存流从字符串对象读取并将其作为流公开 这样就可以很容易地将它们输入到您的邮政编码中。使用ZipEntry和PutNextEntry()。下面显示了

当文件当前在内存中时,是否有方法创建包含多个文件的Zip存档?我想要保存的文件实际上只是文本文件,并且存储在我的应用程序中的字符串类中。但是我想在一个独立的归档中保存多个文件。它们都可以位于归档文件的根目录中


如果能够使用SharpZipLib来实现这一点,那就太好了。

是的,您可以使用SharpZipLib来实现这一点-当您需要提供要写入的流时,使用
内存流

从字符串对象读取并将其作为流公开


这样就可以很容易地将它们输入到您的邮政编码中。

使用
ZipEntry
PutNextEntry()
。下面显示了如何对文件执行此操作,但对于内存中的对象,只需使用MemoryStream即可

FileStream fZip = File.Create(compressedOutputFile);
ZipOutputStream zipOStream = new ZipOutputStream(fZip);
foreach (FileInfo fi in allfiles)
{
    ZipEntry entry = new ZipEntry((fi.Name));
    zipOStream.PutNextEntry(entry);
    FileStream fs = File.OpenRead(fi.FullName);
    try
    {
        byte[] transferBuffer[1024];
        do
        {
            bytesRead = fs.Read(transferBuffer, 0, transferBuffer.Length);
            zipOStream.Write(transferBuffer, 0, bytesRead);
        }
        while (bytesRead > 0);
    }
    finally
    {
        fs.Close();
    }
}
zipOStream.Finish();
zipOStream.Close();
注意这个答案已经过时了;自.NET4.5以来,
ZipArchive
类允许压缩内存中的文件。请参阅以了解如何使用它


您还可以使用一个可序列化的对象来存储所有字符串,这样做会有所不同

[Serializable]
public class MyStrings {
    public string Foo { get; set; }
    public string Bar { get; set; }
}
然后,您可以将其序列化为流以保存它。
为了节省空间,可以使用GZipStream(来自System.IO.Compression)对其进行压缩。(注意:GZip是流压缩,不是多个文件的存档)

当然,如果您需要的是保存数据,而不是将一些文件压缩为其他软件的特定格式。
此外,这将允许您保存除字符串以外的更多类型的数据。

为此使用SharpZipLib似乎相当复杂。这在中国要容易得多。在v1.9中,代码如下所示:

using (ZipFile zip = new ZipFile())
{
    zip.AddEntry("Readme.txt", stringContent1);
    zip.AddEntry("readings/Data.csv", stringContent2);
    zip.AddEntry("readings/Index.xml", stringContent3);
    zip.Save("Archive1.zip"); 
}
上面的代码假设stringContent{1,2,3}包含要存储在zip存档文件(或条目)中的数据。第一个条目是“Readme.txt”,它存储在zip归档文件的顶级“目录”中。接下来的两个条目存储在zip归档文件的“readings”目录中

字符串以默认编码进行编码。这里没有显示AddEntry()的重载,它允许您显式指定要使用的编码

如果内容在流或字节数组中,而不是字符串中,则接受这些类型的AddEntry()会有重载。还有一些重载接受Write委托,这是您的一种方法,被调用以将数据写入zip。例如,这可以方便地将数据集保存到zip文件中


DotNetZip是免费的,开源的。

我遇到了这个问题,使用MSDN示例创建了这个类:

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
using System.IO.Packaging;  
using System.IO;  

public class ZipSticle  
{  
    Package package;  

    public ZipSticle(Stream s)  
    {  
        package = ZipPackage.Open(s, FileMode.Create);  
    }  

    public void Add(Stream stream, string Name)  
    {  
        Uri partUriDocument = PackUriHelper.CreatePartUri(new Uri(Name, UriKind.Relative));  
        PackagePart packagePartDocument = package.CreatePart(partUriDocument, "");  

        CopyStream(stream, packagePartDocument.GetStream());  
        stream.Close();  
    }  

    private static void CopyStream(Stream source, Stream target)  
    {  
        const int bufSize = 0x1000;  
        byte[] buf = new byte[bufSize];  
        int bytesRead = 0;  
        while ((bytesRead = source.Read(buf, 0, bufSize)) > 0)  
            target.Write(buf, 0, bytesRead);  
    }  

    public void Close()  
    {  
        package.Close();  
    }  
}
然后您可以这样使用它:

FileStream str = File.Open("MyAwesomeZip.zip", FileMode.Create);  
ZipSticle zip = new ZipSticle(str);  

zip.Add(File.OpenRead("C:/Users/C0BRA/SimpleFile.txt"), "Some directory/SimpleFile.txt");  
zip.Add(File.OpenRead("C:/Users/C0BRA/Hurp.derp"), "hurp.Derp");  

zip.Close();
str.Close();
您可以将
内存流
(或任何
)传递到
ZipSticle。添加
,例如:

FileStream str = File.Open("MyAwesomeZip.zip", FileMode.Create);  
ZipSticle zip = new ZipSticle(str);  

byte[] fileinmem = new byte[1000];
// Do stuff to FileInMemory
MemoryStream memstr = new MemoryStream(fileinmem);
zip.Add(memstr, "Some directory/SimpleFile.txt");

memstr.Close();
zip.Close();
str.Close();

这个函数应该从数据流创建一个字节数组:为了简单起见,我创建了一个处理文件的简单接口

public interface IHasDocumentProperties
{
    byte[] Content { get; set; }
    string Name { get; set; }
}

public void CreateZipFileContent(string filePath, IEnumerable<IHasDocumentProperties> fileInfos)
{    
    using (var memoryStream = new MemoryStream())
    {
        using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
        {
            foreach(var fileInfo in fileInfos)
            {
                var entry = zipArchive.CreateEntry(fileInfo.Name);

                using (var entryStream = entry.Open())
                {
                    entryStream.Write(fileInfo.Content, 0, fileInfo.Content.Length);
                }                        
            }
        }

        using (var fileStream = new FileStream(filePath, FileMode.OpenOrCreate, System.IO.FileAccess.Write))
        {
            memoryStream.CopyTo(fileStream);
        }
    }
}
公共接口IHasDocumentProperties
{
字节[]内容{get;set;}
字符串名称{get;set;}
}
public void CreateZipFileContent(字符串文件路径、IEnumerable文件信息)
{    
使用(var memoryStream=new memoryStream())
{
使用(var zipArchive=new zipArchive(memoryStream,ZipArchiveMode.Create,true))
{
foreach(fileInfos中的var fileInfo)
{
var entry=zipArchive.CreateEntry(fileInfo.Name);
使用(var entryStream=entry.Open())
{
Write(fileInfo.Content,0,fileInfo.Content.Length);
}                        
}
}
使用(var fileStream=newfilestream(filePath,FileMode.OpenOrCreate,System.IO.FileAccess.Write))
{
memoryStream.CopyTo(文件流);
}
}
}
我通过添加
MemoryStream
s作为不同Excel文件的源来利用它。当我下载zip时,文件中什么都没有。这可能是我们尝试通过AJAX创建和下载文件的方式

为了获得要包含在Zip中的不同Excel文件的内容,我必须将每个文件添加为
字节[]

using (var memoryStream = new MemoryStream())
using (var zip = new ZipFile())
{
    zip.AddEntry("Excel File 1.xlsx", excelFileStream1.ToArray());
    zip.AddEntry("Excel File 2.xlsx", excelFileStream2.ToArray());

    // Keep the file off of disk, and in memory.
    zip.Save(memoryStream);
}

我有点想让保存文件成为一种格式,允许用户打开它,并取出特定的部分,但这可能是最好/最简单的事情…@Configurator很高兴看到你在这里你可以在
zipOStream
上使用“using()”而不是
Close()
?是的,如果您使用.NET 4.5,ZipoutStream是可处理的。有一个内置的Zip类比这个讨厌的类(SharpZipLib)更容易使用。我认为在每次枚举之后(即在
foreach
的末尾),需要
zipOStream.CloseEntry()
)——@TheMuffinMan愿意链接/详细说明替代方案吗?包起来了吗?这很好,只是在内存流被处理后你正在使用它。很好,我现在就把它修好了