Download Files From Azure Blob Cloud Storage With C# (.Net)

Code Snippets 4 U

Download container blobs event if you don’t know the blob names in a container.

// Authorization
StorageCredentials credential = new StorageCredentials(AccountName, AccountKey);
                _account = new CloudStorageAccount(credential, false);
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Blob;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;

namespace AzureBlobDownloaderAndRename
{
    public class AzureBlobStorageFileDownloader
    {
        private readonly string _pathOfStorage;
        private readonly CloudStorageAccount _account;
        private readonly List<ExcelSheetSchema> _filesToDownload;
        private string errors;
        private string nameChangesFile = "D:\\FileNamesChanged.txt";
        private static int Counter = 0; // Will restrict the number of async tasks.
        private string ErrorsFileLog = "D:\\ErrorsFilesLog.txt";
        public AzureBlobStorageFileDownloader(string pathOfStorage,
                                                List<ExcelSheetSchema> filesToDownload,
                                                string AccountName,
                                                string AccountKey)
        {
            _filesToDownload = filesToDownload;
            _pathOfStorage = pathOfStorage;
            if (!string.IsNullOrWhiteSpace(AccountName)
                && !string.IsNullOrWhiteSpace(AccountKey))
            {
                StorageCredentials credential = new StorageCredentials(AccountName, AccountKey);
                _account = new CloudStorageAccount(credential, false);
            }
        }

        /// <summary>
        /// Download the files from Azure container.
        /// It will only download the first file from container blob list.
        /// </summary>
        public void GetFiles()
        {
            if (_account == null)
            {
                Console.WriteLine("\nAccount is null\n");
                return;
            }
            if (string.IsNullOrEmpty(_pathOfStorage) || !Directory.Exists(_pathOfStorage))
            {
                Console.WriteLine("\nFile storage path {0} is invalid\n", _pathOfStorage);
                return;
            }
            var blobClient = _account.CreateCloudBlobClient(); // Create blobClient
            int count = 1;
            _filesToDownload.ForEach(async file =>
           {
               try
               {
                   var container = blobClient.GetContainerReference(file.ContainerName); // get reference to container
                   var continuationToken = new Microsoft.WindowsAzure.Storage.Blob.BlobContinuationToken(); // create a continuation token need for async blob list
                   var blobs = container.ListBlobsSegmentedAsync(continuationToken).Result; // get list of blobs
                   if (blobs.Results.Count() == 0) throw new Exception();
                   var blobFound = blobs.Results.FirstOrDefault(); // as we have only one blob, so used FirstOrDefault
                   if (blobFound == null) throw new Exception();
                   var blobFileInfo = new FileInfo(blobFound.Uri.ToString()); // file
                   var blobName = blobFileInfo.Name; // Find the blob name from Uri
                   var blobDownloadable = container.GetBlobReference(blobName); // Get reference to blob
                   blobDownloadable.FetchAttributesAsync().Wait(); // Fetch the blob information.
                   Counter++;
                   if (Counter > 10)
                   {
                       // wait until Counter is not less Counter
                       while (Counter > 10)
                       {
                           Thread.Sleep(20000); // After every 20 Seconds, the thread will check if total count is less than 10 or not.
                       }
                   }
                   Console.WriteLine("\nDownloading File {0}. {1}, Started At {2}, File Size {3} MB", count, blobName, DateTime.Now, blobDownloadable.Properties.Length / (1024 * 1024));
                   count++;
                   // Download blob to custom file name.
                   try
                   {
                       await DownloadFile(blobDownloadable, $"{file.Title}{blobFileInfo.Extension}");
                       Console.WriteLine("Downloaded {0}", blobDownloadable.Name);
                       Counter--;
                   }
                   catch (Exception)
                   {
                       // save the name of files which are not completed yet.
                       errors += $@"{blobName}\n";
                   }
               }
               catch (Exception)
               {
                   errors += $@"container: {file.ContainerName}\n";
               }

           });
            Console.WriteLine("Below files were not downloaded");
            Console.WriteLine(errors);
            File.AppendAllText(ErrorsFileLog, errors);
        }
	/// Downloads files from azure cloud.
	/// Also checks if same file is there in the list(you can change it to check folder files by changing the function 'CheckIfFileIsRepeated'). 
	/// If there is, then append a number.
        private async Task DownloadFile(CloudBlob cloudBlob, string fileName)
        {
            var newFileName = fileName;
            // check if file name contains invalid characters
            if(fileName.IndexOfAny(Path.GetInvalidFileNameChars()) != -1)
            {
                // create new file name by removing the invalid chars
                newFileName = Regex.Replace(fileName, "[\\/:\" *?<>|]+", "_");
                // create new name and save to text file.
                File.AppendAllText(nameChangesFile, $"{fileName} is renamed to {newFileName}");
            }
            // checks whether file title is repeated
            if (CheckIfFileIsRepeated(fileName))
            {
                int num = 1;
                // rename only if the file is not previously downloaded
                // loop till we don't get unique name
                var tempNewFileName = newFileName;
                tempNewFileName = Path.GetFileNameWithoutExtension(tempNewFileName) + "_" + num + new FileInfo(fileName).Extension;
                while (File.Exists($"{_pathOfStorage}/{tempNewFileName}"))
                {
                    num++;
                    tempNewFileName = Path.GetFileNameWithoutExtension(tempNewFileName) + "_" + num + new FileInfo(fileName).Extension;
                }
                // now put the number at the end
                newFileName = Path.GetFileNameWithoutExtension(newFileName) + "_" + num + new FileInfo(fileName).Extension;
            }
            if (!File.Exists($"{_pathOfStorage}/{newFileName}"))
                await cloudBlob.DownloadToFileAsync($"{_pathOfStorage}/{newFileName}", FileMode.Create);
        }

		/// this checks if our list contains filenames which are repeated
        private bool CheckIfFileIsRepeated(string filename)
        {
                if (_filesToDownload.Where(ll => String.Compare(ll.Title, Path.GetFileNameWithoutExtension(filename), true) == 0).Count() > 1)
                {
                    return true;
                }
                else
                {
                    return false;
                }
        }
	/// checks if file is already appended with x number
        private bool CheckIfFileIsAppenededWithXNumber(int number, string fileNameWithOutExtension)
        {
            var splitedString = fileNameWithOutExtension.Split('_');
            if (splitedString.Length == 0) return false;

            try
            {
                var ch = Convert.ToInt32(splitedString[splitedString.Length - 1]);
                if (ch == number) return true;
                return false;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }
}

This is for reference only. There may be few changes needed as SDK changes. I have used nuget package : unofficial.windowsazure.mediaservices.extensions and targeted .Net core 2.2

Leave a Reply

Your email address will not be published. Required fields are marked *

+ nine = 11