【问题标题】:Why do I get a corrupted *.gz file after creating it with C#?为什么使用 C# 创建 *.gz 文件后会得到损坏的文件?
【发布时间】:2021-06-11 10:18:54
【问题描述】:

我正在开发一个 .NET 5、C# 控制台应用程序,用于从自定义对象列表创建一个 CSV 文件,对其进行 gzip 压缩,然后使用以下代码将其上传到 Azure 存储容器:

var blobServiceClient = new BlobServiceClient("My connection string");
var containerClient = GetBlobContainerClient("My container name");
var config = new CsvConfiguration(CultureInfo.CurrentCulture) { Delimiter = ";", Encoding = Encoding.UTF8 };

var list = new List<FakeModel>
{
   new FakeModel { Field1 = "A", Field2 = "B" },
   new FakeModel { Field1 = "C", Field2 = "D" }
};

await using var memoryStream = new MemoryStream();
await using var streamWriter = new StreamWriter(memoryStream);
await using var csvWriter = new CsvWriter(streamWriter, config);

await csvWriter.WriteRecordsAsync(list);

await using var zip = new GZipStream(memoryStream, CompressionMode.Compress, true);
await memoryStream.CopyToAsync(zip);

memoryStream.Seek(0, SeekOrigin.Begin);
var blockBlob = containerClient.GetBlockBlobClient("test.csv.gz");
await blockBlob.UploadAsync(memoryStream);

它似乎可以工作,但是当我从云端下载 gzip 进行检查时,尝试解压缩时出现以下错误:

检查文件显示它的长度为 0。

你能帮我理解为什么吗?

【问题讨论】:

  • 在上传完成之前,CopyToAsync 方法可能没有完成。
  • 如果您在十六进制编辑器中打开 .gz 文件(例如 Can I hex edit a file in Visual Studio?),它看起来像 .gz 文件吗?
  • @jdweng 我正在等待它。
  • @AndrewMorton 如果我这样打开它,我会得到00000000 作为内容。
  • 我猜 GZipStream 应该在 MemoryStream 和 StreamWriter 之间的写入器堆栈中。所以,CsvWriter -> StreamWriter -> GZipStream -> MemoryStream

标签: c# csv gzip csvhelper gzipstream


【解决方案1】:

new GZipStream 的流参数是 destination 流。要处理输入到输出,您需要以某种方式写入 GZipStream 的实例。

当我尝试使用它时,我发现需要调用csvWriter.FlushAsync()

像这样:

class Program
{
    public class FakeModel
    {
        public string Field1 { get; set; }
        public string Field2 { get; set; }
    }

    static async Task Main(string[] args)
    {
        var config = new CsvConfiguration(CultureInfo.CurrentCulture) { Delimiter = ";", Encoding = Encoding.UTF8 };

        var list = new List<FakeModel>
                        {
                           new FakeModel { Field1 = "A", Field2 = "B" },
                           new FakeModel { Field1 = "C", Field2 = "D" }
                        };

        await using var memoryStream = new MemoryStream();
        await using var streamWriter = new StreamWriter(memoryStream);
        await using var csvWriter = new CsvWriter(streamWriter, config);

        await csvWriter.WriteRecordsAsync(list);
        await csvWriter.FlushAsync();

        memoryStream.Position = 0;

        await using var fs = new FileStream(@"C:\temp\SO67935249.csv.gz", FileMode.Create);
        await using var zip = new GZipStream(fs, CompressionMode.Compress, true);
        await memoryStream.CopyToAsync(zip);

    }
}

【讨论】:

  • 我认为可以通过直接写入 gzipStream 来简化示例,即new Streamwriter(new GzipStream(...))。此外,using var ... 将在方法结束时进行清理,在这种情况下,它的作用域 using 语句可能会更好,我认为这应该避免显式刷新的需要。
猜你喜欢
  • 1970-01-01
  • 2017-03-29
  • 1970-01-01
  • 1970-01-01
  • 2010-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多