AzureTipsAndTricks/blog/tip141.md

4.2 KiB

type title excerpt tags date
post Tip 141 - Generate a Zip file from Azure Blob Storage Files Learn how to easily generate a Zip file from Azure Blob Storage Files
Storage
2018-07-16 17:00:00

::: tip 💡 Learn more : Azure storage account overview. :::

Generate a Zip file from Azure Blob Storage Files

You might have a task that pops up where you need to generate a zip file from a number of files in your Azure blob storage account. For 1 or 2 files, this may not be a problem but for 20-2000, you might want to find a way to automate this.

One option is to zip the files directly to the output stream using the blob streams. If you do this it still means that you are routing the stream through the web server.

To begin you will want a way work with zip easily. I used the latest version of ICSharpZipLib and make sure you pull in the Azure Storage library.

We'll setup our Storage Service which will read from the stream and get a reference to the blob we are currently looping through.

public void ReadToStream(IFileIdentifier file, Stream stream, StorageType storageType = StorageType.Stored, ITenant overrideTenant = null)
{
    var blob = GetBlockBlobClient(file, storageType, overrideTenant);
    blob.DownloadTo(stream);
}

private BlockBlobClient GetBlockBlobClient(IFileIdentifier file, StorageType storageType = StorageType.Stored, ITenant overrideTenant = null)
{
    var filepath = GetFilePath(file, storageType);
    var container = GetTenantContainer(overrideTenant);
    return container.GetBlockBlobClient(filepath);
}

Now we have one method that takes in a response stream and loops through all the files to generate our zip file.

public void ZipFilesToResponse(HttpResponseBase response, IEnumerable<Asset> files, string zipFileName)
{
    using (var zipOutputStream = new ZipOutputStream(response.OutputStream))
    {
        zipOutputStream.SetLevel(0); // 0 - store only to 9 - means best compression
        response.BufferOutput = false;
        response.AddHeader("Content-Disposition", "attachment; filename=" + zipFileName);
        response.ContentType = "application/octet-stream";

        foreach (var file in files)
        {
            var entry = new ZipEntry(file.FilenameSlug())
            {
                DateTime = DateTime.Now,
                Size = file.Filesize
            };
            zipOutputStream.PutNextEntry(entry);
            storageService.ReadToStream(file, zipOutputStream);
            response.Flush();
            if (!response.IsClientConnected)
            {
                break;
            }
        }
        zipOutputStream.Finish();
        zipOutputStream.Close();
    }
    response.End();
}

Another "quick and dirty" MVC sample can be found below. This sample specifies the file names and the zip file name.

public ActionResult Download()
{
    StorageSharedKeyCredential credential = new StorageSharedKeyCredential("<StorageAccountName>", "<StorageAccountKey>");

    BlobServiceClient serviceClient = new BlobServiceClient(new Uri("<StorageAccountUri>"), credential);
    BlobContainerClient container = serviceClient.GetBlobContainerClient("test");

    var blobFileNames = new string[] { "file1.png", "file2.png", "file3.png", "file4.png" };
    using (var zipOutputStream = new ZipOutputStream(Response.OutputStream))
    {
        foreach (var blobFileName in blobFileNames)
        {
            zipOutputStream.SetLevel(0);
            var blob = container.GetBlockBlobClient(blobFileName);
            var entry = new ZipEntry(blobFileName);
            zipOutputStream.PutNextEntry(entry);
            blob.DownloadTo(zipOutputStream);
        }
        zipOutputStream.Finish();
        zipOutputStream.Close();
    }
    Response.BufferOutput = false;
    Response.AddHeader("Content-Disposition", "attachment; filename=" + "zipFileName.zip");
    Response.ContentType = "application/octet-stream";
    Response.Flush();
    Response.End();
    return null;
}