【问题标题】:DotNetZip creates 0kb files when passing in memory streamDotNetZip 在传入内存流时创建 0kb 文件
【发布时间】:2020-03-04 16:56:37
【问题描述】:

我有一个 Razor 页面,我想生成一个包含多个 CSV 文件的 Zip 文件。

当我只想生成一个文件时它工作正常,例如

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"
    };
}

但是当我尝试将两个文件的内存流传递到 DotNetZip 流中时,zip 会下载到浏览器,但两个文件都是 0kb。关于为什么的任何想法?

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"
    };
}

我看过其他 StackOverflow 帖子,人们建议添加 Seek() 函数来重置流的位置,但无论是否存在它都对我不起作用。

调试时,当我调用 zip.AddEntry() 时,我可以看到“bankfileStream”流中有字节,但是当我调用 zip.Save(zipStream) 时,zipStream 显示 0 字节。

任何建议表示赞赏!

【问题讨论】:

  • 尝试在填充后读取前将内存流位置设置为零。
  • 设置哪个内存流?在阅读之前我不是已经将它们设置为零吗?谢谢。
  • 不在此处:等待使用 var internalFileCsvWriter = new CsvWriter(internalFileStreamWriter, CultureInfo.InvariantCulture);

标签: c# dotnetzip


【解决方案1】:

我尝试了许多不同的选项,但在我改用 SharpZipLib 库之前没有任何效果。这是完整的解决方案:

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;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-01
    • 1970-01-01
    • 2012-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多