Create Zip archive from multiple in memory files i

2019-01-21 13:57发布

Is there a way to create a Zip archive that contains multiple files, when the files are currently in memory? The files I want to save are really just text only and are stored in a string class in my application. But I would like to save multiple files in a single self-contained archive. They can all be in the root of the archive.

It would be nice to be able to do this using SharpZipLib.

8条回答
Anthone
2楼-- · 2019-01-21 14:07

I come across this problem, using the MSDN example I created this class:

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();  
    }  
}

You can then use it like this:

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();

You can pass a MemoryStream (or any Stream) to ZipSticle.Add such as:

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();
查看更多
一纸荒年 Trace。
3楼-- · 2019-01-21 14:08

Yes, you can use SharpZipLib to do this - when you need to supply a stream to write to, use a MemoryStream.

查看更多
叛逆
4楼-- · 2019-01-21 14:20

I was utilizing Cheeso's answer by adding MemoryStreams as the source of the different Excel files. When I downloaded the zip, the files had nothing in them. This could be the way we were getting around trying to create and download a file over AJAX.

To get the contents of the different Excel files to be included in the Zip, I had to add each of the files as a byte[].

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);
}
查看更多
在下西门庆
5楼-- · 2019-01-21 14:25

This function should create a byte array from a stream of data: I've created a simple interface for handling files for simplicity

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);
    }
}
查看更多
我欲成王,谁敢阻挡
6楼-- · 2019-01-21 14:26

Use ZipEntry and PutNextEntry() for this. The following shows how to do it for a file, but for an in-memory object just use a 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();
查看更多
劫难
7楼-- · 2019-01-21 14:29

Using SharpZipLib for this seems pretty complicated. This is so much easier in DotNetZip. In v1.9, the code looks like this:

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"); 
}

The code above assumes stringContent{1,2,3} contains the data to be stored in the files (or entries) in the zip archive. The first entry is "Readme.txt" and it is stored in the top level "Directory" in the zip archive. The next two entries are stored in the "readings" directory in the zip archive.

The strings are encoded in the default encoding. There is an overload of AddEntry(), not shown here, that allows you to explicitly specify the encoding to use.

If you have the content in a stream or byte array, not a string, there are overloads for AddEntry() that accept those types. There are also overloads that accept a Write delegate, a method of yours that is invoked to write data into the zip. This works for easily saving a DataSet into a zip file, for example.

DotNetZip is free and open source.

查看更多
登录 后发表回答