有没有一种方法可以创建一个包含多个文件的Zip存档,而这些文件目前在内存中? 我要保存的文件实际上只是纯文本,并且存储在我的应用程序中的字符串类中。 但我希望将多个文件保存在单个自包含存档中。 它们都可以位于存档的根目录中。
如果能使用SharpZipLib实现这一点就太好了。
有没有一种方法可以创建一个包含多个文件的Zip存档,而这些文件目前在内存中? 我要保存的文件实际上只是纯文本,并且存储在我的应用程序中的字符串类中。 但我希望将多个文件保存在单个自包含存档中。 它们都可以位于存档的根目录中。
如果能使用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();
使用SharpZipLib似乎相当复杂。 在DotNetZip中这要简单得多。在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归档文件的顶级"Directory"中。接下来的两个条目存储在zip归档文件的"readings"目录中。
这些字符串使用默认编码进行编码。此处未显示AddEntry()的重载版本,它允许您显式指定要使用的编码。
如果您将内容存储在流或字节数组中而不是字符串中,则有AddEntry()的重载版本接受这些类型。还有一些重载版本可以接受Write委托,即您的方法用于将数据写入zip。例如,这适用于轻松将DataSet保存到zip文件中。
DotNetZip是免费且开源的。
这个函数应该从数据流中创建一个字节数组:我为了简单起见创建了一个处理文件的简单接口。
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.Position = 0;
memoryStream.CopyTo(fileStream);
}
}
}
我遇到了一个问题,使用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();
MemoryStream
(或任何Stream
)传递给ZipSticle.Add
,例如: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();
MemoryStream
。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);
}
请注意,此答案已经过时;自 .Net 4.5 开始,ZipArchive
类允许在内存中压缩文件。有关如何使用,请参见下面johnny 5的答案。
您也可以以稍微不同的方式完成,使用可序列化对象来存储所有字符串。
[Serializable]
public class MyStrings {
public string Foo { get; set; }
public string Bar { get; set; }
}
zipOStream
上使用using()
代替Close()
吗? - Jay Bazuziforeach
结束时)使用zipOStream.CloseEntry()
。-- https://github.com/icsharpcode/SharpZipLib/wiki/Zip-Samples#-create-a-zip-with-full-control-over-contents - drzaus