简体   繁体   English

DotNetZip 在传入内存流时创建 0kb 文件

[英]DotNetZip creates 0kb files when passing in memory stream

I have a Razor page which I want to generate a Zip file containing multiple CSV files.我有一个 Razor 页面,我想生成一个包含多个 CSV 文件的 Zip 文件。

It works fine when I just want to generate one file, eg当我只想生成一个文件时它工作正常,例如

public async Task<FileStreamResult> OnGet(int id)
{
    var bankDetails = _paymentFileGenerator.GeneratePaymentFiles(id);

    await using var memoryStream = new MemoryStream();
    await using var streamWriter = new StreamWriter(memoryStream);
    await using var csvWriter = new CsvWriter(streamWriter, CultureInfo.InvariantCulture)
    {
        Configuration = { HasHeaderRecord = false, }
    };

    csvWriter.WriteRecords(bankDetails);
    streamWriter.Flush();

    return new FileStreamResult(new MemoryStream(memoryStream.ToArray()), new MediaTypeHeaderValue("text/csv"))
    {
        FileDownloadName = "bacs.csv"
    };
}

But when I try to pass memory streams for two files into a DotNetZip stream the zip downloads to the browser but both files are 0kb.但是当我尝试将两个文件的内存流传递到 DotNetZip 流时,zip 会下载到浏览器,但两个文件都是 0kb。 Any thoughts on why?关于为什么的任何想法?

public async Task<FileStreamResult> OnGet(int id)
{
    var bankFiles = _paymentFileGenerator.GeneratePaymentFiles(id);

    using var zipStream = new MemoryStream();
    using var zip = new ZipFile();

    await using var bankFileStream = new MemoryStream();
    await using var bankFileStreamWriter = new StreamWriter(bankFileStream);
    await using var bankFileCsvWriter = new CsvWriter(bankFileStreamWriter, CultureInfo.InvariantCulture)
    {
        Configuration = { HasHeaderRecord = false, }
    };

    bankFileCsvWriter.WriteRecords(bankFiles.BankFile);
    bankFileCsvWriter.Flush();
    bankFileStream.Seek(0, SeekOrigin.Begin);
    zip.AddEntry("bacs.csv", (name, stream) => bankFileStream.ToArray());

    await using var internalFileStream = new MemoryStream();
    await using var internalFileStreamWriter = new StreamWriter(internalFileStream);
    await using var internalFileCsvWriter = new CsvWriter(internalFileStreamWriter, CultureInfo.InvariantCulture);

    internalFileCsvWriter.WriteRecords(bankFiles.InternalFile);
    internalFileCsvWriter.Flush();
    internalFileStream.Seek(0, SeekOrigin.Begin);
    zip.AddEntry("internal.csv", (name, stream) => internalFileStream.ToArray());

    zip.Save(zipStream);

    zipStream.Seek(0, SeekOrigin.Begin);

    return new FileStreamResult(new MemoryStream(zipStream.ToArray()), new MediaTypeHeaderValue("application/zip"))
    {
        FileDownloadName = "paymentbatch.zip"
    };
}

I've seen other StackOverflow posts where people suggested adding the Seek() function to reset the position of the streams but it didn't work for me whether that was there or not.我看过其他 StackOverflow 帖子,其中人们建议添加 Seek() 函数来重置流的位置,但无论是否存在,它对我都不起作用。

When debugging, I can see that the 'bankfileStream' stream has bytes in it when I call the zip.AddEntry() but then the zipStream shows 0 bytes when I call zip.Save(zipStream).调试时,当我调用 zip.AddEntry() 时,我可以看到“bankfileStream”流中有字节,但是当我调用 zip.Save(zipStream) 时,zipStream 显示 0 字节。

Any suggestions appreciated!任何建议表示赞赏!

I tried many different options and nothing worked until I used the SharpZipLib library instead.我尝试了许多不同的选项,但在使用SharpZipLib库之前没有任何效果。 Here is the full solution:这是完整的解决方案:

public async Task<FileStreamResult> OnGet(int id)
{
    var bankFiles = _paymentFileGenerator.GeneratePaymentFiles(id);
    var bankFileBytes = await GetCsvFileBytes(bankFiles.BankFile, includeHeader: false);
    var internalFileBytes = await GetCsvFileBytes(bankFiles.InternalFile);

    var files = new List<AttachedFile>
    {
        new AttachedFile("bacs.csv", bankFileBytes),
        new AttachedFile("internal.csv", internalFileBytes)
    };

    var zipStream = AddFilesToZip(files);

    return new FileStreamResult(zipStream, new MediaTypeHeaderValue("application/zip"))
    {
        FileDownloadName = "paymentbatch.zip"
    };
}

public MemoryStream AddFilesToZip(List<AttachedFile> attachedFiles)
{
    var outputMemStream = new MemoryStream();
    using (var zipStream = new ZipOutputStream(outputMemStream))
    {
        // 0-9, 9 being the highest level of compression
        zipStream.SetLevel(3);

        foreach (var file in attachedFiles)
        {
            var newEntry = new ZipEntry(file.Name) {DateTime = DateTime.Now};

            zipStream.PutNextEntry(newEntry);

            StreamUtils.Copy(new MemoryStream(file.Bytes), zipStream, new byte[4096]);
        }

        zipStream.CloseEntry();

        // Stop ZipStream.Dispose() from also Closing the underlying stream.
        zipStream.IsStreamOwner = false;
    }

    outputMemStream.Position = 0;
    return outputMemStream;
}

private static async Task<byte[]> GetCsvFileBytes<T>(List<T> records, bool includeHeader = true) where T : class
{
    await using var bankFileStream = new MemoryStream();
    await using var bankFileStreamWriter = new StreamWriter(bankFileStream);
    await using var bankFileCsvWriter = new CsvWriter(bankFileStreamWriter, CultureInfo.InvariantCulture)
    {
        Configuration = {HasHeaderRecord = includeHeader}
    };
    bankFileCsvWriter.WriteRecords(records);
    bankFileStreamWriter.Flush();
    return bankFileStream.ToArray();
}

public class AttachedFile
{
    public byte[] Bytes { get; set; }
    public string Name { get; set; }

    public AttachedFile(string name, byte[] bytes)
    {
        Bytes = bytes;
        Name = name;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM