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.