ZipArchive дает неожиданное завершение ошибки данных
Я пытаюсь создать поток zip на лету с некоторыми данными байтового массива и заставить его загружаться с помощью моего действия MVC.
Но загруженный файл всегда выдает следующую поврежденную ошибку при открытии в Windows.
И эта ошибка, когда я пытаюсь извлечь из 7z
Но учтите, что файлы, извлеченные из 7z, не повреждены.
я использую ZipArchive
и ниже мой код.
private byte[] GetZippedPods(IEnumerable<POD> pods, long consignmentID)
{
using (var zipStream = new MemoryStream())
{
//Create an archive and store the stream in memory.
using (var zipArchive = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
{
int index = 1;
foreach (var pod in pods)
{
var zipEntry = zipArchive.CreateEntry($"POD{consignmentID}{index++}.png", CompressionLevel.NoCompression);
using (var originalFileStream = new MemoryStream(pod.ByteData))
{
using (var zipEntryStream = zipEntry.Open())
{
originalFileStream.CopyTo(zipEntryStream);
}
}
}
return zipStream.ToArray();
}
}
}
public ActionResult DownloadPOD(long consignmentID)
{
var pods = _consignmentService.GetPODs(consignmentID);
var fileBytes = GetZippedPods(pods, consignmentID);
return File(fileBytes, MediaTypeNames.Application.Octet, $"PODS{consignmentID}.zip");
}
Что я тут не так делаю.
Любая помощь будет высоко оценена, так как я борюсь с этим целый день.
заранее спасибо
7 ответов
Переехать zipStream.ToArray()
за пределами zipArchive
с помощью.
Причина вашей проблемы в том, что поток буферизован. Есть несколько способов справиться с этим:
- Вы можете установить поток
AutoFlush
собственность наtrue
, - Вы можете вручную позвонить
.Flush()
в потоке.
Или, так как это MemoryStream
и вы используете .ToArray()
, вы можете просто позволить потоку сначала закрыться / удалиться (что мы и сделали, переместив его за пределы using
).
Я избавляюсь от ZipArchive и ошибка решена
public static byte[] GetZipFile(Dictionary<string, List<FileInformation>> allFileInformations)
{
MemoryStream compressedFileStream = new MemoryStream();
//Create an archive and store the stream in memory.
using (var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Create, true))
{
foreach (var fInformation in allFileInformations)
{
var files = allFileInformations.Where(x => x.Key == fInformation.Key).SelectMany(x => x.Value).ToList();
for (var i = 0; i < files.Count; i++)
{
ZipArchiveEntry zipEntry = zipArchive.CreateEntry(fInformation.Key + "/" + files[i].FileName);
var caseAttachmentModel = Encoding.UTF8.GetBytes(files[i].Content);
//Get the stream of the attachment
using (var originalFileStream = new MemoryStream(caseAttachmentModel))
using (var zipEntryStream = zipEntry.Open())
{
//Copy the attachment stream to the zip entry stream
originalFileStream.CopyTo(zipEntryStream);
}
}
}
//i added this line
zipArchive.Dispose();
return compressedFileStream.ToArray();
}
}
public void SaveZipFile(){
var zipFileArray = Global.GetZipFile(allFileInformations);
var zipFile = new MemoryStream(zipFileArray);
FileStream fs = new FileStream(path + "\\111.zip",
FileMode.Create,FileAccess.Write);
zipFile.CopyTo(fs);
zipFile.Flush();
fs.Close();
zipFile.Close();
}
У меня также были проблемы с этим, и я обнаружил, что моя проблема не в создании самого архива, а в том, как я передавал свой запрос GET в AngularJS.
Этот пост помог мне: как скачать zip-файл с помощью angular
Ключ был добавлением responseType: 'arraybuffer'
на мой звонок $http.
factory.serverConfigExportZIP = function () {
return $http({
url: dataServiceBase + 'serverConfigExport',
method: "GET",
responseType: 'arraybuffer'
})
};
У меня была такая же проблема... В этом случае мне просто нужно было переместитьToArray()
(byte[]) из MemoryStream за пределамиusing (var zipArchive = new ZipArchive...
Я думаю, что это необходимо дляusing
относится кZipArchive
полностью закрыть и удалить файл перед преобразованием его в массив байтов
Я знаю, что это вопрос С#, но для управляемого С++ удалите ZipArchive^ после того, как вы закончите с ним, чтобы исправить ошибку.
ZipArchive^ zar = ZipFile::Open(starget, ZipArchiveMode::Create);
ZipFileExtensions::CreateEntryFromFile(zar, sfile1, "file.txt");
ZipFileExtensions::CreateEntryFromFile(zar, sfile2, "file2.txt");
delete zar;
когда я хотел создать zip-файл непосредственно из MemoryStream, который я использовал для ZipArchive, я получал ошибку («неожиданный конец данных» или файл нулевой длины)
есть три момента, чтобы избавиться от этой ошибки
установите для последнего параметра конструктора ZipArchive значение true (он оставляет поток открытым после удаления ZipArchive)
вызовите dispose() в ZipArchive и удалите его вручную.
создайте другой MemoryStream, на основе которого вы установили в конструкторе ZipArchive, вызвав метод ToArray().
вот пример кода:
using (var memoryStream = new MemoryStream())
{
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create,))
{
foreach (var s3Object in objectList.S3Objects)
{
var entry = archive.CreateEntry(s3Object.Key, CompressionLevel.NoCompression);
using (var entryStream = entry.Open())
{
var request = new GetObjectRequest { BucketName = command.BucketName, Key = s3Object.Key };
using (var getObjectResponse = await client.GetObjectAsync(request))
{
await getObjectResponse.ResponseStream.CopyToAsync(entryStream);
}
}
}
archive.Dispose();
using (var fileStream = new FileStream(outputFileName, FileMode.Create, FileAccess.Write))
{
var zipFileMemoryStream = new MemoryStream(memoryStream.ToArray());
zipFileMemoryStream.CopyTo(fileStream);
zipFileMemoryStream.Flush();
fileStream.Close();
zipFileMemoryStream.Close();
}
}
}
Вы можете удалить "using" и использовать методы Dispose и Close, это работает для меня
...
zip.Dispose();
zipStream.Close();
return zipStream.ToArray();