ZipArchive создает недопустимый ZIP файл
Я пытаюсь создать новый 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?
Ответы
Ответ 1
Я нашел ретроспективную, очевидную ошибку в моем коде. ZipArchive должен быть расположен, чтобы заставить его записывать свой контент в его базовый поток. Поэтому мне пришлось сохранить поток в файл после окончания блока использования ZipArchive.
И было важно установить аргумент 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);
}
}
Ответ 2
Во всем своем потоковом объекте вы должны перематывать потоки с самого начала, чтобы они были правильно прочитаны другими приложениями с использованием метода .Seek.
Пример:
zipStream.Seek(0, SeekOrigin.Begin);
Ответ 3
Вы можете следовать той же идее, только в обратном порядке, используя поток файлов, такой как источник. Я сделал форму ниже, и файл был открыт нормально:
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
}
}
Ответ 4
// 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
, чтобы избежать взаимодействия с уже расположенными ресурсами.
Ответ 5
Полный код выглядит следующим образом:
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.");
}
}
}
Ответ 6
В моем случае проблема заключалась в том, что я не использовал "zipArchive" при завершении задачи zip файла. Даже если я смывал и закрывал все потоки.
Итак, либо используйте, как предложено в ответах выше
using (var zipArchive = new ZipArchive(File.OpenWrite("archive.zip"),
ZipArchiveMode.Create))
Или избавиться от переменной в конце задачи...
zipArchive.Dispose();