Transferir dados com a biblioteca do Movimento de Dados

Nota

Este artigo inclui orientações para trabalhar com a versão 2.0.XX da biblioteca de Movimentação de Dados de Armazenamento do Azure. A versão 2.0.XX está atualmente no modo de manutenção e a biblioteca está recebendo apenas correções para problemas de integridade e segurança de dados. Nenhuma nova funcionalidade ou recurso será adicionado e novas versões do serviço de armazenamento não serão suportadas pela biblioteca.

Versões beta de uma biblioteca moderna do Data Movement estão atualmente em desenvolvimento. Para obter mais informações, consulte Biblioteca de cliente comum de movimentação de dados de armazenamento do Azure para .NET no GitHub.

A biblioteca de Movimentação de Dados de Armazenamento do Azure é uma biblioteca de código aberto multiplataforma projetada para upload, download e cópia de blobs e arquivos de alto desempenho. A biblioteca de Movimentação de Dados fornece métodos convenientes que não estão disponíveis na biblioteca de cliente do Armazenamento do Azure para .NET. Esses métodos fornecem a capacidade de definir o número de operações paralelas, acompanhar o progresso da transferência, retomar facilmente uma transferência cancelada e muito mais.

Essa biblioteca também usa o .NET Core, o que significa que você pode usá-lo ao criar aplicativos .NET para Windows, Linux e macOS. Para saber mais sobre o .NET Core, consulte a documentação do .NET Core. Essa biblioteca também funciona para aplicativos tradicionais do .NET Framework para Windows.

Este documento demonstra como criar um aplicativo de console .NET Core que é executado no Windows, Linux e macOS e executa os seguintes cenários:

  • Carregue arquivos e diretórios para o Armazenamento de Blobs.
  • Defina o número de operações paralelas ao transferir dados.
  • Acompanhe o progresso da transferência de dados.
  • Retomar a transferência de dados cancelada.
  • Copie o arquivo do URL para o Armazenamento de Blobs.
  • Copie do Armazenamento de Blobs para o Armazenamento de Blobs.

Pré-requisitos

Configuração

  1. Visite o Guia de Instalação do .NET Core para instalar o SDK do .NET Core. Ao selecionar seu ambiente, escolha a opção de linha de comando.
  2. Na linha de comando, crie um diretório para seu projeto. Navegue até este diretório e digite dotnet new console -o <sample-project-name> para criar um projeto de console em C#.
  3. Abra este diretório no Visual Studio Code. Esta etapa pode ser feita rapidamente através da linha de comando, digitando code . no Windows.
  4. Instale a extensão C# do Visual Studio Code Marketplace. Reinicie o Visual Studio Code.
  5. Neste ponto, você verá dois prompts. Uma delas é para adicionar "ativos necessários para construir e depurar". Clique em "sim". Outro prompt é para restaurar dependências não resolvidas. Clique em "restaurar".
  6. Modifique launch.json em .vscode para usar o terminal externo como um console. Esta definição deve ler-se como "console": "externalTerminal"
  7. O Visual Studio Code permite depurar aplicativos .NET Core. Pressione F5 para executar seu aplicativo e verifique se sua configuração está funcionando. Você deve ver "Hello World!" impresso no console.

Adicionar a biblioteca de Movimentação de Dados ao seu projeto

  1. Adicione a versão mais recente da biblioteca de movimentação de dados à dependencies seção do seu <project-name>.csproj arquivo. No momento da redação deste artigo, esta versão seria "Microsoft.Azure.Storage.DataMovement": "0.6.2"
  2. Um prompt deve ser exibido para restaurar seu projeto. Clique no botão "restaurar". Você também pode restaurar seu projeto a partir da linha de comando digitando o comando dotnet restore na raiz do diretório do projeto.

Modificar <project-name>.csproj:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>netcoreapp2.0</TargetFramework>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="Microsoft.Azure.Storage.DataMovement" Version="0.6.2" />
        </ItemGroup>
    </Project>

Configurar o esqueleto da sua aplicação

A primeira coisa que fazemos é configurar o código "esqueleto" da nossa aplicação. Esse código nos solicita um nome de conta de armazenamento e uma chave de conta e usa essas credenciais para criar um CloudStorageAccount objeto. Este objeto é utilizado para interagir com a nossa conta de Armazenamento em todos os cenários de transferência. O código também nos pede para escolher o tipo de operação de transferência que gostaríamos de executar.

Modificar Program.cs:

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using Microsoft.Azure.Storage;
using Microsoft.Azure.Storage.Blob;
using Microsoft.Azure.Storage.DataMovement;

namespace DMLibSample
{
    public class Program
    {
        public static void Main()
        {
            Console.WriteLine("Enter Storage account name:");
            string accountName = Console.ReadLine();

            Console.WriteLine("\nEnter Storage account key:");
            string accountKey = Console.ReadLine();

            string storageConnectionString = "DefaultEndpointsProtocol=https;AccountName=" + accountName + ";AccountKey=" + accountKey;
            CloudStorageAccount account = CloudStorageAccount.Parse(storageConnectionString);

            ExecuteChoice(account);
        }

        public static void ExecuteChoice(CloudStorageAccount account)
        {
            Console.WriteLine("\nWhat type of transfer would you like to execute?\n1. Local file --> Azure Blob\n2. Local directory --> Azure Blob directory\n3. URL (e.g. Amazon S3 file) --> Azure Blob\n4. Azure Blob --> Azure Blob");
            int choice = int.Parse(Console.ReadLine());

            if(choice == 1)
            {
                TransferLocalFileToAzureBlob(account).Wait();
            }
            else if(choice == 2)
            {
                TransferLocalDirectoryToAzureBlobDirectory(account).Wait();
            }
            else if(choice == 3)
            {
                TransferUrlToAzureBlob(account).Wait();
            }
            else if(choice == 4)
            {
                TransferAzureBlobToAzureBlob(account).Wait();
            }
        }

        public static async Task TransferLocalFileToAzureBlob(CloudStorageAccount account)
        {

        }

        public static async Task TransferLocalDirectoryToAzureBlobDirectory(CloudStorageAccount account)
        {

        }

        public static async Task TransferUrlToAzureBlob(CloudStorageAccount account)
        {

        }

        public static async Task TransferAzureBlobToAzureBlob(CloudStorageAccount account)
        {

        }
    }
}

Carregar um arquivo local para um blob

Adicione os métodos GetSourcePath e GetBlob a Program.cs:

public static string GetSourcePath()
{
    Console.WriteLine("\nProvide path for source:");
    string sourcePath = Console.ReadLine();

    return sourcePath;
}

public static CloudBlockBlob GetBlob(CloudStorageAccount account)
{
    CloudBlobClient blobClient = account.CreateCloudBlobClient();

    Console.WriteLine("\nProvide name of Blob container:");
    string containerName = Console.ReadLine();
    CloudBlobContainer container = blobClient.GetContainerReference(containerName);
    container.CreateIfNotExistsAsync().Wait();

    Console.WriteLine("\nProvide name of new Blob:");
    string blobName = Console.ReadLine();
    CloudBlockBlob blob = container.GetBlockBlobReference(blobName);

    return blob;
}

Modifique o TransferLocalFileToAzureBlob método:

public static async Task TransferLocalFileToAzureBlob(CloudStorageAccount account)
{
    string localFilePath = GetSourcePath();
    CloudBlockBlob blob = GetBlob(account);
    Console.WriteLine("\nTransfer started...");
    await TransferManager.UploadAsync(localFilePath, blob);
    Console.WriteLine("\nTransfer operation complete.");
    ExecuteChoice(account);
}

Esse código nos solicita o caminho para um arquivo local, o nome de um contêiner novo ou existente e o nome de um novo blob. O TransferManager.UploadAsync método executa o upload usando essas informações.

Clique para F5 executar seu aplicativo. Você pode verificar se o carregamento ocorreu exibindo sua conta de armazenamento com o Gerenciador de Armazenamento do Microsoft Azure.

Definir o número de operações paralelas

Um recurso oferecido pela biblioteca de movimentação de dados é a capacidade de definir o número de operações paralelas para aumentar a taxa de transferência de dados. Por padrão, a biblioteca de movimentação de dados define o número de operações paralelas como 8 * o número de núcleos em sua máquina.

Tenha em mente que muitas operações paralelas em um ambiente de baixa largura de banda podem sobrecarregar a conexão de rede e, na verdade, impedir que as operações sejam totalmente concluídas. Você precisará experimentar essa configuração para determinar o que funciona melhor com base na largura de banda de rede disponível.

Vamos adicionar algum código que nos permita definir o número de operações paralelas. Vamos também adicionar código que cronometra quanto tempo leva para a transferência ser concluída.

Adicione um SetNumberOfParallelOperations método a Program.cs:

public static void SetNumberOfParallelOperations()
{
    Console.WriteLine("\nHow many parallel operations would you like to use?");
    string parallelOperations = Console.ReadLine();
    TransferManager.Configurations.ParallelOperations = int.Parse(parallelOperations);
}

Modifique o ExecuteChoice método para usar SetNumberOfParallelOperations:

public static void ExecuteChoice(CloudStorageAccount account)
{
    Console.WriteLine("\nWhat type of transfer would you like to execute?\n1. Local file --> Azure Blob\n2. Local directory --> Azure Blob directory\n3. URL (e.g. Amazon S3 file) --> Azure Blob\n4. Azure Blob --> Azure Blob");
    int choice = int.Parse(Console.ReadLine());

    SetNumberOfParallelOperations();

    if(choice == 1)
    {
        TransferLocalFileToAzureBlob(account).Wait();
    }
    else if(choice == 2)
    {
        TransferLocalDirectoryToAzureBlobDirectory(account).Wait();
    }
    else if(choice == 3)
    {
        TransferUrlToAzureBlob(account).Wait();
    }
    else if(choice == 4)
    {
        TransferAzureBlobToAzureBlob(account).Wait();
    }
}

Modifique o TransferLocalFileToAzureBlob método para usar um temporizador:

public static async Task TransferLocalFileToAzureBlob(CloudStorageAccount account)
{
    string localFilePath = GetSourcePath();
    CloudBlockBlob blob = GetBlob(account);
    Console.WriteLine("\nTransfer started...");
    Stopwatch stopWatch = Stopwatch.StartNew();
    await TransferManager.UploadAsync(localFilePath, blob);
    stopWatch.Stop();
    Console.WriteLine("\nTransfer operation completed in " + stopWatch.Elapsed.TotalSeconds + " seconds.");
    ExecuteChoice(account);
}

Acompanhe o progresso da transferência

Saber quanto tempo levou para os dados serem transferidos é útil. No entanto, ser capaz de ver o progresso da transferência durante a operação de transferência seria ainda melhor. Para alcançar esse cenário, precisamos criar um TransferContext objeto. O TransferContext objeto vem em duas formas: SingleTransferContext e DirectoryTransferContext. O primeiro é para transferir um único arquivo e o segundo é para transferir um diretório de arquivos.

Adicione os métodos GetSingleTransferContext e GetDirectoryTransferContext a Program.cs:

public static SingleTransferContext GetSingleTransferContext(TransferCheckpoint checkpoint)
{
    SingleTransferContext context = new SingleTransferContext(checkpoint);

    context.ProgressHandler = new Progress<TransferStatus>((progress) =>
    {
        Console.Write("\rBytes transferred: {0}", progress.BytesTransferred );
    });

    return context;
}

public static DirectoryTransferContext GetDirectoryTransferContext(TransferCheckpoint checkpoint)
{
    DirectoryTransferContext context = new DirectoryTransferContext(checkpoint);

    context.ProgressHandler = new Progress<TransferStatus>((progress) =>
    {
        Console.Write("\rBytes transferred: {0}", progress.BytesTransferred );
    });

    return context;
}

Modifique o TransferLocalFileToAzureBlob método para usar GetSingleTransferContext:

public static async Task TransferLocalFileToAzureBlob(CloudStorageAccount account)
{
    string localFilePath = GetSourcePath();
    CloudBlockBlob blob = GetBlob(account);
    TransferCheckpoint checkpoint = null;
    SingleTransferContext context = GetSingleTransferContext(checkpoint);
    Console.WriteLine("\nTransfer started...\n");
    Stopwatch stopWatch = Stopwatch.StartNew();
    await TransferManager.UploadAsync(localFilePath, blob, null, context);
    stopWatch.Stop();
    Console.WriteLine("\nTransfer operation completed in " + stopWatch.Elapsed.TotalSeconds + " seconds.");
    ExecuteChoice(account);
}

Retomar uma transferência cancelada

Outro recurso conveniente oferecido pela biblioteca Data Movement é a capacidade de retomar uma transferência cancelada. Vamos adicionar algum código que nos permite cancelar temporariamente a transferência digitando ce, em seguida, retomar a transferência 3 segundos depois.

Modificar TransferLocalFileToAzureBlob:

public static async Task TransferLocalFileToAzureBlob(CloudStorageAccount account)
{
    string localFilePath = GetSourcePath();
    CloudBlockBlob blob = GetBlob(account);
    TransferCheckpoint checkpoint = null;
    SingleTransferContext context = GetSingleTransferContext(checkpoint);
    CancellationTokenSource cancellationSource = new CancellationTokenSource();
    Console.WriteLine("\nTransfer started...\nPress 'c' to temporarily cancel your transfer...\n");

    Stopwatch stopWatch = Stopwatch.StartNew();
    Task task;
    ConsoleKeyInfo keyinfo;
    try
    {
        task = TransferManager.UploadAsync(localFilePath, blob, null, context, cancellationSource.Token);
        while(!task.IsCompleted)
        {
            if(Console.KeyAvailable)
            {
                keyinfo = Console.ReadKey(true);
                if(keyinfo.Key == ConsoleKey.C)
                {
                    cancellationSource.Cancel();
                }
            }
        }
        await task;
    }
    catch(Exception e)
    {
        Console.WriteLine("\nThe transfer is canceled: {0}", e.Message);
    }

    if(cancellationSource.IsCancellationRequested)
    {
        Console.WriteLine("\nTransfer will resume in 3 seconds...");
        Thread.Sleep(3000);
        checkpoint = context.LastCheckpoint;
        context = GetSingleTransferContext(checkpoint);
        Console.WriteLine("\nResuming transfer...\n");
        await TransferManager.UploadAsync(localFilePath, blob, null, context);
    }

    stopWatch.Stop();
    Console.WriteLine("\nTransfer operation completed in " + stopWatch.Elapsed.TotalSeconds + " seconds.");
    ExecuteChoice(account);
}

Até agora, o nosso checkpoint valor sempre foi definido para null. Agora, se cancelarmos a transferência, recuperamos o último ponto de verificação da nossa transferência e, em seguida, usamos este novo ponto de verificação no nosso contexto de transferência.

Transferir um diretório local para o armazenamento de Blob

Seria dececionante se a biblioteca Data Movement pudesse transferir apenas um arquivo de cada vez. Felizmente, não é esse o caso. A biblioteca Data Movement fornece a capacidade de transferir um diretório de arquivos e todos os seus subdiretórios. Vamos adicionar algum código que nos permita fazer exatamente isso.

Primeiro, adicione o método GetBlobDirectory a Program.cs:

public static CloudBlobDirectory GetBlobDirectory(CloudStorageAccount account)
{
    CloudBlobClient blobClient = account.CreateCloudBlobClient();

    Console.WriteLine("\nProvide name of Blob container. This can be a new or existing Blob container:");
    string containerName = Console.ReadLine();
    CloudBlobContainer container = blobClient.GetContainerReference(containerName);
    container.CreateIfNotExistsAsync().Wait();

    CloudBlobDirectory blobDirectory = container.GetDirectoryReference("");

    return blobDirectory;
}

Em seguida, modifique TransferLocalDirectoryToAzureBlobDirectory:

public static async Task TransferLocalDirectoryToAzureBlobDirectory(CloudStorageAccount account)
{
    string localDirectoryPath = GetSourcePath();
    CloudBlobDirectory blobDirectory = GetBlobDirectory(account);
    TransferCheckpoint checkpoint = null;
    DirectoryTransferContext context = GetDirectoryTransferContext(checkpoint);
    CancellationTokenSource cancellationSource = new CancellationTokenSource();
    Console.WriteLine("\nTransfer started...\nPress 'c' to temporarily cancel your transfer...\n");

    Stopwatch stopWatch = Stopwatch.StartNew();
    Task task;
    ConsoleKeyInfo keyinfo;
    UploadDirectoryOptions options = new UploadDirectoryOptions()
    {
        Recursive = true
    };

    try
    {
        task = TransferManager.UploadDirectoryAsync(localDirectoryPath, blobDirectory, options, context, cancellationSource.Token);
        while(!task.IsCompleted)
        {
            if(Console.KeyAvailable)
            {
                keyinfo = Console.ReadKey(true);
                if(keyinfo.Key == ConsoleKey.C)
                {
                    cancellationSource.Cancel();
                }
            }
        }
        await task;
    }
    catch(Exception e)
    {
        Console.WriteLine("\nThe transfer is canceled: {0}", e.Message);
    }

    if(cancellationSource.IsCancellationRequested)
    {
        Console.WriteLine("\nTransfer will resume in 3 seconds...");
        Thread.Sleep(3000);
        checkpoint = context.LastCheckpoint;
        context = GetDirectoryTransferContext(checkpoint);
        Console.WriteLine("\nResuming transfer...\n");
        await TransferManager.UploadDirectoryAsync(localDirectoryPath, blobDirectory, options, context);
    }

    stopWatch.Stop();
    Console.WriteLine("\nTransfer operation completed in " + stopWatch.Elapsed.TotalSeconds + " seconds.");
    ExecuteChoice(account);
}

Existem algumas diferenças entre este método e o método para carregar um único ficheiro. Agora estamos usando TransferManager.UploadDirectoryAsync e o getDirectoryTransferContext método que criamos anteriormente. Além disso, agora fornecemos um options valor para nossa operação de upload, o que nos permite indicar que queremos incluir subdiretórios em nosso upload.

Copiar um arquivo do URL para um blob

Agora, vamos adicionar código que nos permite copiar um arquivo de uma URL para um Blob do Azure.

Modificar TransferUrlToAzureBlob:

public static async Task TransferUrlToAzureBlob(CloudStorageAccount account)
{
    Uri uri = new Uri(GetSourcePath());
    CloudBlockBlob blob = GetBlob(account);
    TransferCheckpoint checkpoint = null;
    SingleTransferContext context = GetSingleTransferContext(checkpoint);
    CancellationTokenSource cancellationSource = new CancellationTokenSource();
    Console.WriteLine("\nTransfer started...\nPress 'c' to temporarily cancel your transfer...\n");

    Stopwatch stopWatch = Stopwatch.StartNew();
    Task task;
    ConsoleKeyInfo keyinfo;
    try
    {
        task = TransferManager.CopyAsync(uri, blob, CopyMethod.ServiceSideAsyncCopy, null, context, cancellationSource.Token);
        while(!task.IsCompleted)
        {
            if(Console.KeyAvailable)
            {
                keyinfo = Console.ReadKey(true);
                if(keyinfo.Key == ConsoleKey.C)
                {
                    cancellationSource.Cancel();
                }
            }
        }
        await task;
    }
    catch(Exception e)
    {
        Console.WriteLine("\nThe transfer is canceled: {0}", e.Message);
    }

    if(cancellationSource.IsCancellationRequested)
    {
        Console.WriteLine("\nTransfer will resume in 3 seconds...");
        Thread.Sleep(3000);
        checkpoint = context.LastCheckpoint;
        context = GetSingleTransferContext(checkpoint);
        Console.WriteLine("\nResuming transfer...\n");
        await TransferManager.CopyAsync(uri, blob, CopyMethod.ServiceSideAsyncCopy, null, context, cancellationSource.Token);
    }

    stopWatch.Stop();
    Console.WriteLine("\nTransfer operation completed in " + stopWatch.Elapsed.TotalSeconds + " seconds.");
    ExecuteChoice(account);
}

Um caso de uso importante para esse recurso é quando você precisa mover dados de outro serviço de nuvem (por exemplo, AWS) para o Azure. Contanto que você tenha uma URL que lhe dê acesso ao recurso, você pode facilmente mover esse recurso para Blobs do Azure usando o TransferManager.CopyAsync método. Esse método também introduz um parâmetro CopyMethod . A tabela a seguir mostra as opções disponíveis para esse parâmetro:

Nome do membro valor Description
SyncCopy 0 Transfira dados da origem para a memória e carregue os dados da memória para o destino. Atualmente disponível apenas para cópia de um recurso de Armazenamento do Azure para outro.
ServiceSideAsyncCopy 1 Enviar uma solicitação de cópia inicial para o Armazenamento do Azure para permitir que ele faça a cópia; Monitore o progresso da operação de cópia até que a cópia seja concluída.
ServiceSideSyncCopy 2 Copie o conteúdo de cada bloco com Put Block From URL, Append Block From URL ou Put Page From URL.

Copiar um blob

Outro recurso fornecido exclusivamente pela biblioteca de Movimentação de Dados é a capacidade de copiar de um recurso de Armazenamento do Azure para outro.

Modificar TransferAzureBlobToAzureBlob:

public static async Task TransferAzureBlobToAzureBlob(CloudStorageAccount account)
{
    CloudBlockBlob sourceBlob = GetBlob(account);
    CloudBlockBlob destinationBlob = GetBlob(account);
    TransferCheckpoint checkpoint = null;
    SingleTransferContext context = GetSingleTransferContext(checkpoint);
    CancellationTokenSource cancellationSource = new CancellationTokenSource();
    Console.WriteLine("\nTransfer started...\nPress 'c' to temporarily cancel your transfer...\n");

    Stopwatch stopWatch = Stopwatch.StartNew();
    Task task;
    ConsoleKeyInfo keyinfo;
    try
    {
        task = TransferManager.CopyAsync(sourceBlob, destinationBlob, CopyMethod.SyncCopy, null, context, cancellationSource.Token);
        while(!task.IsCompleted)
        {
            if(Console.KeyAvailable)
            {
                keyinfo = Console.ReadKey(true);
                if(keyinfo.Key == ConsoleKey.C)
                {
                    cancellationSource.Cancel();
                }
            }
        }
        await task;
    }
    catch(Exception e)
    {
        Console.WriteLine("\nThe transfer is canceled: {0}", e.Message);
    }

    if(cancellationSource.IsCancellationRequested)
    {
        Console.WriteLine("\nTransfer will resume in 3 seconds...");
        Thread.Sleep(3000);
        checkpoint = context.LastCheckpoint;
        context = GetSingleTransferContext(checkpoint);
        Console.WriteLine("\nResuming transfer...\n");
        await TransferManager.CopyAsync(sourceBlob, destinationBlob, CopyMethod.SyncCopy, null, context, cancellationSource.Token);
    }

    stopWatch.Stop();
    Console.WriteLine("\nTransfer operation completed in " + stopWatch.Elapsed.TotalSeconds + " seconds.");
    ExecuteChoice(account);
}

Neste exemplo, definimos o parâmetro booleano como TransferManager.CopyAsyncCopyMethod.SyncCopy para indicar que queremos fazer uma cópia síncrona. Isso significa que o recurso é baixado primeiro para nossa máquina local e, em seguida, carregado no Blob do Azure. A opção de cópia síncrona é uma ótima maneira de garantir que sua operação de cópia tenha uma velocidade consistente. Em contraste, a velocidade de uma cópia assíncrona do lado do servidor depende da largura de banda de rede disponível no servidor, que pode flutuar. No entanto, a cópia síncrona pode gerar um custo de saída adicional em comparação com a cópia assíncrona. A abordagem recomendada é usar a cópia síncrona em uma VM do Azure que esteja na mesma região da sua conta de armazenamento de origem para evitar custos de saída.

O aplicativo de movimentação de dados agora está completo. O exemplo de código completo está disponível no GitHub.

Próximos passos

Documentação de referência da biblioteca de Movimentação de Dados de Armazenamento do Azure.

Gorjeta

Gerencie os recursos de armazenamento de Blob do Azure com o Gerenciador de Armazenamento do Azure. O Azure Storage Explorer é um aplicativo autônomo gratuito da Microsoft que permite gerenciar recursos de armazenamento de Blob do Azure. Usando o Gerenciador de Armazenamento do Azure, você pode criar, ler, atualizar e excluir visualmente contêineres de blob e blobs, bem como gerenciar o acesso aos seus contêineres e blobs de blobs.