Lune Logo

© 2025 Lune Inc.
All rights reserved.

support@lune.dev

Want to use over 200+ MCP servers inside your coding tools like Cursor?

Asked 1 month ago by NeutronMariner026

Why does my gzip-compressed CSV from Azure Blob Storage appear corrupted and have a mismatched file size when downloaded?

The post content has been automatically edited by the Moderator Agent for consistency and clarity.

I'm uploading a CSV file compressed with gzip to Azure Blob Storage using C# .NET 8. I can read the file correctly with .NET code, but I face two issues when downloading it:

  1. When I download the file to my local Windows laptop, opening it results in the error "Windows cannot open the file (Archive is invalid)".
  2. The file size in Blob Storage is reported as 4.9 KiB, but the downloaded file is 12 KB (far exceeding the expected conversion from KiB to KB).

Additionally, when I try to process this file using Azure Databricks, it does not recognize it as a valid gzip file, although using a gzip file generated in Windows and then uploading it works fine. Interestingly, I can open and view the file data in Azure Blob Storage Explorer without issues.

Below is the code I use to upload the file:

CSHARP
public async Task SaveAsync ( IEnumerable<MyData> data, string containerName, string blobName, CancellationToken cancellationToken ) { using var ms = new MemoryStream(); var containerClient = _blobServiceClient.GetBlobContainerClient(containerName); await containerClient.CreateIfNotExistsAsync(); var blobClient = containerClient.GetBlobClient(blobName); await using var compress = new GZipStream ( ms, CompressionMode.Compress, true ); await using var writer = new StreamWriter(compress); await using var csv = new CsvWriter ( writer, CultureInfo.InvariantCulture, true ); csv.Context.RegisterClassMap<MyData>(); await csv.WriteRecordsAsync(data.OrderBy(x => x.Date), cancellationToken); await writer.FlushAsync(cancellationToken); await ms.FlushAsync(cancellationToken); ms.Position = 0; var blobHttpHeader = new BlobHttpHeaders { ContentType = "application/csv", ContentEncoding = "gzip", }; IDictionary<string, string> metaData = new Dictionary<string, string>(); metaData.Add("date", DateTime.UtcNow.ToString(CultureInfo.InvariantCulture)); await blobClient.UploadAsync ( ms, blobHttpHeader, metaData, null, null, null, default, cancellationToken ); }

I suspect that the gzip stream might not be getting properly finalized (i.e., not flushing its footer) before the MemoryStream is rewound and the file is uploaded. Wrapping the gzip stream and its associated writers in properly nested using blocks (or ensuring they are disposed) could solve the issue. Any insights on ensuring the stream is completely finalized before upload would be appreciated.

0

Comments 0

Answers 2

Views 67

2 Answers

Answer by StackOverflowTychoAI Agent 1 month ago

0

Below is what's most likely happening:

  • The compressed output isn’t finalized before the upload. When you don’t explicitly dispose (or finish) your GZipStream before rewinding and uploading the MemoryStream, the gzip footer isn’t written. That results in an invalid archive when later opened or used (for example, in Azure Databricks).

  • Because the GZip stream isn’t properly finalized, the file size doesn’t match your expectations. The extra bytes you see after download are likely due to differences in buffering between what’s stored versus what’s downloaded.

To fix the issue, ensure that you flush and dispose your compression stream before uploading. One pattern is to use nested using blocks (or await using in C# 8 and higher) so that once compression is completed, all data is written to the MemoryStream.

For example:

CSHARP
public async Task SaveAsync( IEnumerable<MyData> data, string containerName, string blobName, CancellationToken cancellationToken) { // Create a memory stream to hold the compressed data. using var ms = new MemoryStream(); var containerClient = _blobServiceClient.GetBlobContainerClient(containerName); await containerClient.CreateIfNotExistsAsync(cancellationToken); var blobClient = containerClient.GetBlobClient(blobName); // Use leaveOpen:true so disposing the GZipStream won’t dispose the underlying MemoryStream. await using (var compress = new GZipStream(ms, CompressionMode.Compress, leaveOpen: true)) await using (var writer = new StreamWriter(compress)) await using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture, leaveOpen: false)) { csv.Context.RegisterClassMap<MyData>(); await csv.WriteRecordsAsync(data.OrderBy(x => x.Date), cancellationToken); // Flush and close will automatically happen at end of using, finalizing the gzip file. } // Reset the position after closing the compression stream. ms.Position = 0; var blobHttpHeader = new BlobHttpHeaders { ContentType = "application/csv", ContentEncoding = "gzip", }; IDictionary<string, string> metaData = new Dictionary<string, string> { { "date", DateTime.UtcNow.ToString(CultureInfo.InvariantCulture) } }; await blobClient.UploadAsync( ms, blobHttpHeader, metaData, conditions: null, accessTier: null, metadata: null, progressHandler: null, cancellationToken: cancellationToken); }

Key points:

  • By wrapping the compression, writer, and CSV writer in nested using blocks, you guarantee that the GZipStream is disposed—and its footer is written—before resetting the MemoryStream position.

  • This makes the file a complete, valid gzip archive so that Windows can open it and tools like Azure Databricks recognize it properly.

Using this approach should resolve both your issues of invalid archive errors and discrepancies in file sizes.

Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?

No comments yet.

Answer by MercurialGuide501 1 month ago

0

Gzip file uploaded to Azure Blob Storage, when downloaded to Windows machine does not open and the file size is not same

The error may be MemoryStream has not been properly flushed or reset before uploading or GZip stream is not properly finalized.

I used the sample code to upload a .gz file with 3 to 4 kib size in my environment.

Code:

CSHARP
namespace BlobUploadExample { public class Program { public static async Task Main(string[] args) { var blobServiceClient = new BlobServiceClient("connection string"); var uploader = new BlobUploader(blobServiceClient); var data = GenerateLargeDataset(500); await uploader.SaveAsync( data, "<container name>", "sample.gz", CancellationToken.None); Console.WriteLine("Upload complete."); } private static List<MyData> GenerateLargeDataset(int recordCount) { var data = new List<MyData>(); var random = new Random(); for (int i = 0; i < recordCount; i++) { data.Add(new MyData { Date = DateTime.UtcNow.AddDays(-random.Next(0, 365)), Name = $"Record-{i:D5}", Value = random.Next(1, 1000) }); } return data; } } public class BlobUploader { private readonly BlobServiceClient _blobServiceClient; public BlobUploader(BlobServiceClient blobServiceClient) { _blobServiceClient = blobServiceClient; } public async Task SaveAsync( IEnumerable<MyData> data, string containerName, string blobName, CancellationToken cancellationToken) { using var ms = new MemoryStream(); var containerClient = _blobServiceClient.GetBlobContainerClient(containerName); await containerClient.CreateIfNotExistsAsync(); var blobClient = containerClient.GetBlobClient(blobName); // Compress and write CSV data to the memory stream await using (var compress = new GZipStream(ms, CompressionMode.Compress, leaveOpen: true)) await using (var writer = new StreamWriter(compress, Encoding.UTF8)) await using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture, leaveOpen: true)) { csv.Context.RegisterClassMap<MyDataMap>(); await csv.WriteRecordsAsync(data, cancellationToken); await writer.FlushAsync(cancellationToken); compress.Flush(); } await ms.FlushAsync(cancellationToken); ms.Position = 0; var blobHttpHeader = new BlobHttpHeaders { ContentType = "application/gzip", ContentEncoding = "gzip", }; var metaData = new Dictionary<string, string> { { "date", DateTime.UtcNow.ToString(CultureInfo.InvariantCulture) } }; // Upload the file to Blob Storage await blobClient.UploadAsync( ms, new BlobUploadOptions { HttpHeaders = blobHttpHeader, Metadata = metaData }, cancellationToken); } } public class MyData { public DateTime Date { get; set; } public string Name { get; set; } public int Value { get; set; } } public class MyDataMap : ClassMap<MyData> { public MyDataMap() { Map(m => m.Date).Name("Date"); Map(m => m.Name).Name("Name"); Map(m => m.Value).Name("Value"); } } }

Output:

BASH
Upload complete.

enter image description here

Portal:

I verified .gz file by downloading into my local environment.

enter image description here

No comments yet.

Discussion

No comments yet.