Вопрос в том, как я могу на лету создать заархивированную (сжатую) папку с помощью веб-API ASP.NET Core 2 (в настоящее время)?
Я использую System.IO.Compression.ZipArchive
У меня было несколько сообщений в блогах, где это делается с использованием потоков или байтовых массивов, и все они дают мне одинаковый результат.
Я могу загрузить zip-папку, но не могу ее открыть.
Заархивированная папка имеет правильный размер. Хотя он не открывается.
Я хочу, чтобы это работало, когда пользователь нажимает кнопку, которая запускает это действие, и возвращает заархивированную папку, содержащую один или несколько файлов.
[HttpGet]
[Route("/api/download/zip")]
public async Task<IActionResult> Zip()
{
byte[] bytes = null;
using (MemoryStream zipStream = new MemoryStream())
using (var zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
{
var tempFileName = await _azure.GetFilesByRef("Azure_FilePath");
// Running just this line gives me the zipped folder (empty) which I can open
ZipArchiveEntry entry = zip.CreateEntry("File1.pdf", CompressionLevel.Fastest);
// Adding this 2nd section will download the zip but will not open the zip folder
using (Stream stream = entry.Open())
using (FileStream fs = new FileStream(tempFileName, FileMode.Open, FileAccess.Read))
{
await fs.CopyToAsync(stream);
}
bytes = zipStream.ToArray();
}
return File(bytes, MediaTypeNames.Application.Zip, $"Attachments{DateTime.Now.ToBinary()}.zip");
}
Может ли кто-нибудь заметить ошибку или предложить альтернативное решение?
Неясно, пытаетесь ли вы создать zip и отправить его по трубе, или вы пытаетесь получить zip из лазурного и передать его.
Вы должны добавить запись для каждого элемента, который хотите добавить в архив.
@poke да, я могу скачать файл напрямую с лазурного сервера, но это не та функциональность, которую я хочу.
Я говорил о постепенном изменении вашего кода, чтобы вы могли понять, в чем проблема.





Все данные не записываются в поток, пока архив не будет удален. Таким образом, в этом случае данные в потоке могут быть неполными, если архив еще не сбросил их.
memoryStream.ToArray вызывается до того, как архив получит возможность сбросить все свои данные в базовый поток.
Рассмотрите возможность рефакторинга до
//...
var tempFileName = await _azure.GetFilesByRef("Azure_FilePath");
using (MemoryStream zipStream = new MemoryStream()) {
using (var archive = new ZipArchive(zipStream, ZipArchiveMode.Create, leaveOpen: true)) {
ZipArchiveEntry entry = archive.CreateEntry("File1.pdf", CompressionLevel.Fastest);
using (Stream stream = entry.Open())
using (FileStream fs = new FileStream(tempFileName, FileMode.Open, FileAccess.Read)) {
await fs.CopyToAsync(stream);
}
}// disposal of archive will force data to be written to memory stream.
zipStream.Position = 0; //reset memory stream position.
bytes = zipStream.ToArray(); //get all flushed data
}
//...
В вашем примере также предполагается, что открытый FileStream является файлом правильного типа для созданной записи; Один файл PDF. В противном случае рассмотрите возможность извлечения имени из tempFileName.
Вы должны добавить уникальную запись (путь к файлу) для каждого элемента, который хотите добавить в архив.
Это работает, если вы отправляете файл напрямую из лазурного? Без застежки? Работает ли он с локальным файлом, полученным не из Azure? Имеет ли смысл размер файла zip-архива?