0

I would like to Copy a file across Azure containers without using azcopy utility. Please help with the script(Spring boot or .net example).

I was able to upload\download file from\to local from\to container. Now wondering, how I could achieve remote to remote copy.

Following code is working fine. All I need now is remote copy.

using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Microsoft.Azure.Storage.Blob;
using System;
using System.IO;
using System.Threading.Tasks;

namespace whizlabblob
{
    class Program
    {
        static string storageconnstring = "DefaultEndpointsProtocol=https;AccountName=mainices;AccountKey=********************";
        static string containerName = "demo";
        static string filename = "sample.txt";
        static string filepath="C:\\Work\\sample.txt";
        static string downloadpath = "C:\\Work\\sample2.txt";
        static async Task Main(string[] args)
        {
            //Container().Wait();
            //CreateBlob().Wait();
            //GetBlobs().Wait();
            // GetBlob().Wait();
            Console.WriteLine("Complete");
            Console.ReadKey();
        }

        static async Task Container()
        {
         
            BlobServiceClient blobServiceClient = new BlobServiceClient(storageconnstring);
         
            BlobContainerClient containerClient = await blobServiceClient.CreateBlobContainerAsync(containerName);
        }



        static async Task CreateBlob()
        {
            
            BlobServiceClient blobServiceClient = new BlobServiceClient(storageconnstring);
            
            BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(containerName);
            
            BlobClient blobClient = containerClient.GetBlobClient(filename);            
            using FileStream uploadFileStream = File.OpenRead(filepath);
            

            await blobClient.UploadAsync(uploadFileStream, true);
            uploadFileStream.Close();
        }


        static async Task GetBlobs()
        {
            
            BlobServiceClient blobServiceClient = new BlobServiceClient(storageconnstring);
            
            BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(containerName);
            
            
            await foreach (BlobItem blobItem in containerClient.GetBlobsAsync())
            {
                Console.WriteLine("\t" + blobItem.Name);
            }

        }

        static async Task GetBlob()
        {
            
            BlobServiceClient blobServiceClient = new BlobServiceClient(storageconnstring);
            
            BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(containerName);
            
            BlobClient blob = containerClient.GetBlobClient(filename);
            
            BlobDownloadInfo blobdata = await blob.DownloadAsync();

            
            using (FileStream downloadFileStream = File.OpenWrite(downloadpath))
            {
                await blobdata.Content.CopyToAsync(downloadFileStream);
                downloadFileStream.Close();
            }


            // Read the new file
            using (FileStream downloadFileStream = File.OpenRead(downloadpath))
            {
                using var strreader = new StreamReader(downloadFileStream);
                string line;
                while ((line = strreader.ReadLine()) != null)
                {
                    Console.WriteLine(line);
                }
            }

        }
    }
}
ecstasy
  • 161
  • 1
  • 2
  • 9

1 Answers1

2

You were almost there :). In order to copy a blob from one container to another, you just need to create an instance of BlobClient for a blob in the target container and call StartCopyFromUriAsync method and pass the URI of the source blob.

Here's the code to do that:

    static async Task CopyBlob()
    {
        BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString);

        BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(containerName);

        BlobClient blobClient = containerClient.GetBlobClient(filename);
        var blobUri = blobClient.Uri;

        BlobContainerClient targetContainerClient = blobServiceClient.GetBlobContainerClient("demo-copy");//This is the container where we want to copy the blob
        BlobClient targetBlobClient = targetContainerClient.GetBlobClient(filename);
        await targetBlobClient.StartCopyFromUriAsync(blobUri);
    }

A few things to keep in mind:

  • Because you're copying blob in the same storage account, you just need the source blob's URI. However if you're copying blobs across storage account, you will need to ensure that the URI you provide to copy method should be publicly accessible.
  • Again because you're copying blob in the same storage account, the server-side copy operation is synchronous. If you're copying blob across storage account, the operation is asynchronous and may take some time to finish. You must wait for the copy operation to finish before taking any action on the source blob (like deleting it).
Gaurav Mantri
  • 128,066
  • 12
  • 206
  • 241
  • Thank you Gaurav so much .. You are a life saver .. it worked like a charm. However - I have a bigger problem .. I am a java microservices guy .. don't know .net much .. there are 2 pending tasks .. one this upon execution - I want the URL of newly coped file .. (guess that would be easy) .. 2nd .. right now it is working locally .. i want to run it remotely .. i know these must be baby tasks for you .. but could you please guide ? – ecstasy Jun 26 '20 at 13:06
  • when I am trying to run exact same code as Azure function .. I am getting this error - 2020-06-26T13:16:29Z [Error] run.csx(8,1): error CS7021: Cannot declare namespace in script code 2020-06-26T13:17:17Z [Error] run.csx(57,13): error CS0246: The type or namespace name 'BlobClient' could not be found (are you missing a using directive or an assembly reference?) – ecstasy Jun 26 '20 at 13:19
  • 1
    Please see this link for the error: https://github.com/scriptcs/scriptcs/issues/1078#issuecomment-643055424. – Gaurav Mantri Jun 26 '20 at 13:22
  • Thanks for the link ... towards the end it says - there is no solution to it .. – ecstasy Jun 26 '20 at 13:52
  • 1
    I believe you will need to use C# in .Net Class library instead of C# Script for you Azure Function. You can read more about it here: https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-class-library. HTH. – Gaurav Mantri Jun 26 '20 at 13:59
  • not able to figure that out :( .. like I said I am a java guy .. don't know the difference b/w c# and c# script .. have made a new thread ... thanks for all your help Gaurav https://stackoverflow.com/questions/62596741/azure-function-not-working-cannot-declare-namespace-in-script-code – ecstasy Jun 26 '20 at 14:20
  • 1
    Think of it a compiled v/s interpreted code (not a good analogy but like Java v/s JavaScript). So your C# Function code is compiled. This you write in Visual Studio, compile the code and then deploy the binaries. C# Script code is something you write directly in Azure Portal. Even I am not too familiar with C# Script code. I have only written C# Compiled code for my Azure Functions. HTH. – Gaurav Mantri Jun 26 '20 at 14:23
  • 1
    When copying across storage accounts which are not publicly available you could also attach a SAS token to the source URI.Quote: `However, if the source is a blob in another account, the source blob must either be public or must be authenticated via a shared access signature. If the source blob is public, no authentication is required to perform the copy operation.`. Source: https://learn.microsoft.com/en-us/dotnet/api/azure.storage.blobs.specialized.blobbaseclient.startcopyfromuriasync?view=azure-dotnet – Orhan May 07 '21 at 04:19