分享方式:


透過資料移動程式庫傳輸資料

注意

本文包含使用 Azure 儲存體資料行動程式庫 2.0.XX 版的指導。 2.0.XX 版目前處於維護模式,而且程式庫只會接收資料完整性和安全性問題的修正程式。 不會新增新功能或特性,而且程式庫不支援新的儲存體服務版本。

新式資料移動程式庫的 Beta 版本目前正在開發中。 如需詳細資訊,請參閱 GitHub 上的 適用於 .NET 的 Azure 儲存體 Movement Common 用戶端程式庫

Azure 儲存體資料移動程式庫是跨平台開放原始碼程式庫,專為高效能上傳、下載及複製 Blob 和檔案而設計。 資料移動程式庫提供了無法在適用於 .NET 的 Azure 儲存體用戶端程式庫中使用的便捷方法。 這些方法可讓您設定平行作業數目、追蹤傳輸進度、輕鬆繼續取消的傳輸等等。

此程式庫也會使用 .NET Core,這表示您在建置適用於 Windows、Linux 和 macOS 的 .NET 應用程式時可以使用它。 若要深入了解 .NET Core,請參閱 .NET Core 文件 (英文)。 這個程式庫也適用於 Windows 的傳統 .NET 架構應用程式。

本文件將示範如何建立可在 Windows、Linux 和 macOS 上執行的 .NET Core 主控台應用程式,並執行下列案例:

  • 將檔案和目錄上傳至 Blob 儲存體。
  • 定義傳輸資料時的平行作業數目。
  • 追蹤資料傳輸進度。
  • 繼續已取消的資料傳輸。
  • 將檔案從 URL 複製到 Blob 儲存體。
  • 從 Blob 儲存體複製到 Blob 儲存體。

必要條件

設定

  1. 如需安裝 .NET Core SDK,請參閱 .NET Core 安裝指南。 選取環境時,請選擇命令列選項。
  2. 從命令列為專案建立目錄。 瀏覽到此目錄中,然後輸入 dotnet new console -o <sample-project-name> 以建立 C# 主控台專案。
  3. 在 Visual Studio Code 中開啟此目錄。 您可以透過在 Windows 中於命令列輸入 code . 來快速完成此步驟。
  4. 從 Visual Studio Code Marketplace 安裝 C# 擴充功能 (英文)。 重新啟動 Visual Studio Code。
  5. 這時,您應該會看到兩個提示。 其中一個是新增「建置和偵錯所需的資產」。選取 [是]。另一個提示是還原未解析的相依性。 選取 [還原]。
  6. 修改 .vscode 下的 launch.json 以將外部終端機作為主控台。 這項設定應讀取為 "console": "externalTerminal"
  7. Visual Studio Code 可讓您偵錯 .NET Core 應用程式。 按 F5 以執行應用程式,並確定您的設定運作正常。 您應該會看到 "Hello World!" 列印至主控台。

將資料移動程式庫新增至專案

  1. 將最新版本的資料移動程式庫新增至 <project-name>.csproj 檔案的 dependencies 區段。 撰寫本文時,此版本為 "Microsoft.Azure.Storage.DataMovement": "0.6.2"
  2. 您應該會看到提示顯示以還原專案。 選取 [還原] 按鈕。 您也可以在專案目錄的根目錄中輸入命令 dotnet restore,來從命令列還原專案。

修改 <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>

設定應用程式架構

我們做的第一件事是為應用程式設定程式碼架構。 此程式代碼會提示我們輸入記憶體帳戶名稱和帳戶金鑰,並使用這些認證來建立 CloudStorageAccount 物件。 此物件可用來在所有傳輸案例中與我們的記憶體帳戶互動。 該程式碼也會提示我們選擇要執行的傳輸作業類型。

修改 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)
        {

        }
    }
}

重要

此程式代碼範例會使用 連接字串 來授權存取記憶體帳戶。 此組態適用於範例用途。 應用程式程式代碼中應謹慎使用連接字串和帳戶存取金鑰。 如果帳戶存取金鑰遺失或意外放在不安全的地方,您的服務可能變得易受攻擊。 任何擁有存取金鑰的人都可以授權執行目標為儲存體帳戶的要求,而且可實質存取所有資料。

將本機檔案上傳至 Blob

將方法 GetSourcePathGetBlob 加入到 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;
}

修改 TransferLocalFileToAzureBlob 方法:

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);
}

此程式碼會提示我們輸入本機檔案的路徑、新的或現有容器的名稱,和新的 Blob 的名稱。 TransferManager.UploadAsync 方法會利用此資訊執行上傳。

F5 以執行應用程式。 您可以使用 Microsoft Azure 儲存體總管檢視儲存體帳戶,確認是否有上傳。

設定平行作業的數目

數據移動連結庫可讓您設定平行作業數目,以增加數據傳輸輸送量。 根據預設,資料移動程式庫將平行作業的數目設為機器核心數的 8 倍。

請記住,低頻寬環境中的許多平行作業可能會使網路連線不堪重負,並實際防止作業完全完成。 您應該試驗此設定,以根據可用的網路頻寬來判斷最適合哪些專案。

在此範例中,我們會新增可讓我們設定平行作業數目的程序代碼。 我們也新增程式代碼,此程式代碼會花費多少時間完成傳輸。

SetNumberOfParallelOperations 方法加入到 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);
}

修改 ExecuteChoice 方法以使用 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();
    }
}

修改 TransferLocalFileToAzureBlob 方法以使用計時器:

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);
}

追蹤傳輸進度

您可以藉由建立 TransferContext 物件,在傳輸作業期間追蹤傳輸的進度。 物件 TransferContext 有兩種形式: SingleTransferContext 用於單一檔傳輸,以及 DirectoryTransferContext 目錄傳輸。

將方法 GetSingleTransferContextGetDirectoryTransferContext 加入到 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;
}

修改 TransferLocalFileToAzureBlob 方法以使用 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);
}

繼續已取消的傳輸

數據移動連結庫所提供的另一項功能是能夠繼續取消傳輸。 接下來,我們會新增一些程式代碼,讓我們輸入 來暫時取消傳輸 c,然後在 3 秒後繼續傳輸。

修改 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);
}

到目前為止,我們的 checkpoint 值已設定為 null。 現在,如果我們取消傳輸,我們會擷取傳輸的最後一個檢查點,然後在新的傳輸內容中使用這個新的檢查點。

將本機目錄傳送至 Blob 儲存體

數據移動連結庫可讓您傳輸檔案目錄及其所有子目錄,如下列範例所示。

首先,將方法 GetBlobDirectory 加入 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;
}

然後,修改 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);
}

這個方法與上傳單一檔案的方法有一些差異。 我們現在使用 TransferManager.UploadDirectoryAsync 和稍早建立的 getDirectoryTransferContext 方法。 此外,我們現在會提供 options 值給上傳作業,這可讓我們指出要在上傳中包含的子目錄。

將檔案從 URL 複製到 Blob

現在,讓我們加入程式碼,以從 URL 將檔案複製到 Azure Blob。

修改 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);
}

這項功能的重要使用案例是當您需要將數據從另一個雲端服務移至 Azure 時。 如果您有可存取資源的 URL,您可以使用 方法輕鬆地將該資源移至 Azure Blob TransferManager.CopyAsync 。 此方法也會引進 CopyMethod 參數。 下表顯示此參數的可用選項:

成員名稱 Description
SyncCopy 0 從來源下載資料到記憶體,並將資料從記憶體上傳至目的地。 目前僅適用於從某個 Azure 儲存體資源複製到另一個 Azure 儲存體。
ServiceSideAsyncCopy 1 將開始複製要求傳送至 Azure 儲存體,讓它進行複製; 監視複製作業進度,直到複製完成為止。
ServiceSideSyncCopy 2 使用 Put Block From URLAppend Block From URLPut Page From URL 複製每個區塊的內容。

複製 Blob

數據移動連結庫所提供的另一項功能是能夠從某個 Azure 儲存體 資源複製到另一個資源。

修改 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);
}

在此範例中,我們將 TransferManager.CopyAsync 中的布林值參數設為 CopyMethod.SyncCopy,指出我們要執行同步複製。 此設定表示資源會先下載到本機計算機,然後再上傳至 Azure Blob。 同步複製選項是確保複製作業有一致速度的絕佳方式。 相較之下,非同步伺服器端複製取決於伺服器的可用網路頻寬,速度可能會有所變動。 不過,相較於異步複製,同步複製可能會產生額外的輸出成本。 建議的方法是在與來源記憶體帳戶位於相同區域中的 Azure 虛擬機中使用同步複製,以避免輸出成本。

資料移動應用程式現在已完成。 您可在 GitHub 上取得完整的程式碼範例

下一步

Azure 儲存體資料移動程式庫參考文件

提示

使用 Azure 儲存體總管來管理 Azure Blob 儲存體資源。 Azure 儲存體總管是一個 Microsoft 提供的免費獨立應用程式,可讓您管理 Azure Blob 儲存體資源。 使用 Azure 儲存體總管,您能夠以視覺化方式建立、讀取、更新和刪除 Blob 容器和 Blob,以及管理對 Blob 容器和 Blob 的存取權。