Copy Files with Directory Structure from Azure Blob to File Share

Hello and welcome to this blog which shows you how to copy files and folders with the same hierarchy from Azure blob to Azure file share using c#. This article lets you copy files without downloading them to the local system. So, without further delay, will dive directly into a code snippet.

First, connect to the container using the connection string and get the container reference from where the files are to be copied.

private BlobContainerClient GetBlobContainerClient()
{
    BlobServiceClient blobServiceClient = new BlobServiceClient("Storage-connection-string-from-Azure");
    return blobServiceClient.GetBlobContainerClient("container-name");
}

After getting the container reference, the next step is to list all the blobs inside the container

public async IAsyncEnumerable<BlobClient> GetAllBlobsAsync(string prefix) // prefix : folder under a container to list the files
{
    var container = GetBlobContainerClient();
    await foreach (BlobItem page in container.GetBlobsAsync(BlobTraits.None, BlobStates.None, prefix))
    {
        yield return container.GetBlobClient(page.Name);
    }
}

Then loop through the blobs to copy to Azure file share as below. We fetch the URI for each file/blob and pass it to the file share service to copy.

public async Task ImportDocsFromBlobToFileShare(string blobName)
{
    IAsyncEnumerable<BlobClient> lstBlobClients = _blobService.GetAllBlobsAsync(blobName);
    await foreach (var item in lstBlobClients)
    {
        Uri blobSas = item.GenerateSasUri(
            Azure.Storage.Sas.BlobSasPermissions.Read,
            DateTime.UtcNow.AddHours(2)
        ); // SAS Uri is optional
        await _fileShareService.CopyFromURI(blobSas, item.Name);
    }
}
public async Task CopyFromURI(Uri uri, string fileName)
{
    ShareClient shareClient = new ShareClient(
        fileShareConnectionString,
        fileShareName
    ); // connect to azure file share with connection string and file share name
    ShareDirectoryClient targetDirectoryClient = await GetSubDirectory(shareClient, uri);
    // if the file is under nested folders, create those folders first and copy the file.
    ShareFileClient fileClient = targetDirectoryClient.GetFileClient(
        fileName.Substring(fileName.LastIndexOf('/') + 1)
    );
    await fileClient.StartCopyAsync(uri);
}
private async Task<ShareDirectoryClient> GetSubDirectory(ShareClient shareClient, Uri uri)
{
    ShareDirectoryClient shareDirectoryClient = shareClient.GetRootDirectoryClient();
    var directories = uri.AbsolutePath
        .Trim('/')
        .Split('/')
        .SkipLast(1); // this skip is to exclude the file name and just fetch directory hierarchy
    foreach (string directory in directories)
    {
        shareDirectoryClient = shareDirectoryClient.GetSubDirectoryClient(directory);
        await shareDirectoryClient.CreateIfNotExistsAsync();
    }
    return shareDirectoryClient;
}

That's it....and you are good to go. This worked like a charm to me. May be we can fine tune this, but this does serve the purpose.