Создание Zip-архива из нескольких файлов памяти в С#
Есть ли способ создать Zip-архив, содержащий несколько файлов, когда файлы находятся в памяти? Файлы, которые я хочу сохранить, на самом деле являются только текстовыми и хранятся в классе строк в моем приложении. Но я хотел бы сохранить несколько файлов в одном автономном архиве. Все они могут быть в корне архива.
Было бы неплохо сделать это, используя SharpZipLib.
Ответы
Ответ 1
Используйте для этого 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();
Ответ 2
Использование SharpZipLib для этого кажется довольно сложным. Это намного проще в DotNetZip. В версии 1.1 код выглядит следующим образом:
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-архиве.
Строки кодируются в кодировке по умолчанию. Существует перегрузка AddEntry(), которая не показана здесь, что позволяет явно указывать используемую кодировку.
Если у вас есть контент в потоковом или байтовом массиве, а не в строке, есть перегрузки для AddEntry(), которые принимают эти типы. Существуют также перегрузки, которые принимают делегат Write, метод, который вызывается для записи данных в zip. Это работает для удобства сохранения DataSet в zip файле, например.
DotNetZip является бесплатным и открытым исходным кодом.
Ответ 3
Да, вы можете использовать SharpZipLib для этого - когда вам нужно предоставить поток для записи, используйте MemoryStream
.
Ответ 4
Я сталкиваюсь с этой проблемой, используя пример 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();
Ответ 5
Обратите внимание, что этот ответ устарел; так как .Net 4.5, класс ZipArchive
позволяет делать zip файлы в памяти. Подробнее о том, как его использовать, см. johnny 5.
Вы также можете сделать это несколько иначе, используя объект Serializable для хранения всех строк
[Serializable]
public class MyStrings {
public string Foo { get; set; }
public string Bar { get; set; }
}
Затем вы можете сериализовать его в поток, чтобы сохранить его.
Чтобы сэкономить место, вы можете использовать GZipStream (From System.IO.Compression), чтобы сжать его. (примечание: GZip - это сжатие потока, а не архив из нескольких файлов).
То есть, конечно, если вам действительно нужно сохранять данные, а не зашивать несколько файлов в определенном формате для другого программного обеспечения.
Кроме того, это позволит вам сохранить гораздо больше типов данных, кроме строк.
Ответ 6
Эта функция должна создать массив байтов из потока данных: я создал простой интерфейс для обработки файлов для простоты
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);
}
}
Ответ 7
Я использовал ответ Cheeso, добавив MemoryStream
в качестве источника для разных файлов Excel. Когда я загружал zip, в них ничего не было. Это может быть способ, которым мы пытались создать и загрузить файл через AJAX.
Чтобы содержимое различных файлов Excel было включено в Zip, мне пришлось добавить каждый из файлов в качестве 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);
}
Ответ 8
Используйте StringReader для чтения из ваших строковых объектов и выставляйте их как Stream.
Это должно облегчить отправку их на ваш zip-код.