使用 .NET 上传 Blob

本文介绍如何使用适用于 .NET 的 Azure 存储客户端库上传 Blob。 可以通过文件路径、流、二进制对象或文本字符串将数据上传到块 Blob。 还可以打开 Blob 流并向其写入,或上传块中的大型 Blob。

先决条件

设置你的环境

如果没有现有项目,请查看本部分,其中介绍如何设置项目来使用适用于 .NET 的 Azure Blob 存储客户端库。 步骤包括安装包、添加 using 指令,以及创建已授权的客户端对象。 有关详细信息,请参阅 Azure Blob 存储和 .NET 入门

安装包

从项目目录中,使用 dotnet add package 命令安装 Azure Blob 存储和 Azure 标识客户端库的包。 与 Azure 服务的无密码连接需要 Azure.Identity 包。

dotnet add package Azure.Storage.Blobs
dotnet add package Azure.Identity

添加 using 指令

将这些 using 指令添加到代码文件的顶部:

using Azure.Identity;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Blobs.Specialized;

本文中的某些代码示例可能需要其他 using 指令。

创建客户端对象

若要将应用连接到 Blob 存储,请创建 BlobServiceClient 的实例。 以下示例演示如何使用 DefaultAzureCredential 创建客户端对象进行授权:

public BlobServiceClient GetBlobServiceClient(string accountName)
{
    BlobServiceClient client = new(
        new Uri($"https://{accountName}.blob.core.chinacloudapi.cn"),
        new DefaultAzureCredential());

    return client;
}

可以在 .NET 应用中为依赖项注入注册服务客户端。

还可以为特定容器Blob 创建客户端对象。 要详细了解如何创建和管理客户端对象,请参阅 创建和管理与数据资源交互的客户端对象

授权

授权机制必须具有上传 blob 所需的权限。 若要使用 Microsoft Entra ID 进行授权(建议),需要 Azure RBAC 内置角色“存储 Blob 数据参与者”或更高级别的角色。 若要了解详细信息,请参阅有关放置 Blob (REST API)放置块 (REST API) 的授权指南。

将数据上传到块 Blob

可以使用以下任一方法将数据上传到块 Blob:

使用这些上传方法时,客户端库可以调用 Put Blob 或者调用一系列 Put Block,后跟 Put Block List。 此行为取决于对象的总体大小和数据传输选项的设置方式。

要在 Blob 存储中打开流并向该流写入,可使用以下任一方法:

通过本地文件路径上传块 Blob

以下示例通过本地文件路径上传了块 Blob:

public static async Task UploadFromFileAsync(
    BlobContainerClient containerClient,
    string localFilePath)
{
    string fileName = Path.GetFileName(localFilePath);
    BlobClient blobClient = containerClient.GetBlobClient(fileName);

    await blobClient.UploadAsync(localFilePath, true);
}

通过流式传输上传块 Blob

下面的示例通过创建对象并上传该流上传了块 Blob。

public static async Task UploadFromStreamAsync(
    BlobContainerClient containerClient,
    string localFilePath)
{
    string fileName = Path.GetFileName(localFilePath);
    BlobClient blobClient = containerClient.GetBlobClient(fileName);

    FileStream fileStream = File.OpenRead(localFilePath);
    await blobClient.UploadAsync(fileStream, true);
    fileStream.Close();
}

通过 BinaryData 对象上传块 Blob

以下示例通过 BinaryData 对象上传了块 Blob。

public static async Task UploadFromBinaryDataAsync(
    BlobContainerClient containerClient,
    string localFilePath)
{
    string fileName = Path.GetFileName(localFilePath);
    BlobClient blobClient = containerClient.GetBlobClient(fileName);

    FileStream fileStream = File.OpenRead(localFilePath);
    BinaryReader reader = new BinaryReader(fileStream);

    byte[] buffer = new byte[fileStream.Length];
    reader.Read(buffer, 0, buffer.Length);
    BinaryData binaryData = new BinaryData(buffer);

    await blobClient.UploadAsync(binaryData, true);

    fileStream.Close();
}

通过字符串上传块 Blob

以下示例通过字符串上传了块 Blob:

public static async Task UploadFromStringAsync(
    BlobContainerClient containerClient,
    string blobName)
{
    BlobClient blobClient = containerClient.GetBlobClient(blobName);
    string blobContents = "Sample blob data";

    await blobClient.UploadAsync(BinaryData.FromString(blobContents), overwrite: true);
}

上传到 Blob 存储中的流

你可以在 Blob 存储中打开一个流并向其写入。 以下示例会在 Blob 存储中创建一个 zip 文件并向其写入文件。 不是在本地内存中生成一个 zip 文件,而是一次只在内存中生成一个文件。

public static async Task UploadToStreamAsync(
    BlobContainerClient containerClient,
    string localDirectoryPath)
{
    string zipFileName = Path.GetFileName(
        Path.GetDirectoryName(localDirectoryPath)) + ".zip";

    BlockBlobClient blockBlobClient = containerClient.GetBlockBlobClient(zipFileName);

    using (Stream stream = await blockBlobClient.OpenWriteAsync(true))
    {
        using (ZipArchive zip = new ZipArchive(stream, ZipArchiveMode.Create, leaveOpen: false))
        {
            foreach (var fileName in Directory.EnumerateFiles(localDirectoryPath))
            {
                using (var fileStream = File.OpenRead(fileName))
                {
                    var entry = zip.CreateEntry(
                        Path.GetFileName(fileName), CompressionLevel.Optimal);
                    using (var innerFile = entry.Open())
                    {
                        await fileStream.CopyToAsync(innerFile);
                    }
                }
            }
        }
    }
}

使用配置选项上传块 blob

上传 blob 时,可以定义客户端库配置选项。 可以优化这些选项以提高性能、增强可靠性和优化成本。 以下代码示例演示如何在调用 upload 方法时使用 BlobUploadOptions 来定义配置选项。

在上传时指定数据传输选项

可以在 StorageTransferOptions 中配置值,以提高数据传输操作的性能。 下面的代码示例演示如何设置 StorageTransferOptions 的值,以及如何将选项作为 BlobUploadOptions 实例的一部分包含在内。 此示例中提供的值不作为建议。 若要正确优化这些值,需要考虑应用的特定需求。

public static async Task UploadWithTransferOptionsAsync(
    BlobContainerClient containerClient,
    string localFilePath)
{
    string fileName = Path.GetFileName(localFilePath);
    BlobClient blobClient = containerClient.GetBlobClient(fileName);

    var transferOptions = new StorageTransferOptions
    {
        // Set the maximum number of parallel transfer workers
        MaximumConcurrency = 2,

        // Set the initial transfer length to 8 MiB
        InitialTransferSize = 8 * 1024 * 1024,

        // Set the maximum length of a transfer to 4 MiB
        MaximumTransferSize = 4 * 1024 * 1024
    };

    var uploadOptions = new BlobUploadOptions()
    {
        TransferOptions = transferOptions
    };

    FileStream fileStream = File.OpenRead(localFilePath);
    await blobClient.UploadAsync(fileStream, uploadOptions);
    fileStream.Close();
}

若要详细了解如何优化数据传输选项,请参阅使用 .NET 对上传和下载进行性能优化

在上传时指定传输验证选项

可以指定传输验证选项,以帮助确保正确上传数据并且在传输过程中未被篡改。 可以使用 BlobClientOptions 在客户端级别定义传输验证选项,它会将验证选项应用于从 BlobClient 实例调用的所有方法。

还可以使用 BlobUploadOptions 在方法级别替代传输验证选项。 下面的代码示例演示如何创建 BlobUploadOptions 对象并指定用于生成校验和的算法。 然后,服务使用校验和来验证已上传内容的数据完整性。

public static async Task UploadWithChecksumAsync(
    BlobContainerClient containerClient,
    string localFilePath)
{
    string fileName = Path.GetFileName(localFilePath);
    BlobClient blobClient = containerClient.GetBlobClient(fileName);

    var validationOptions = new UploadTransferValidationOptions
    {
        ChecksumAlgorithm = StorageChecksumAlgorithm.Auto
    };

    var uploadOptions = new BlobUploadOptions()
    {
        TransferValidation = validationOptions
    };

    FileStream fileStream = File.OpenRead(localFilePath);
    await blobClient.UploadAsync(fileStream, uploadOptions);
    fileStream.Close();
}

下表显示了 StorageChecksumAlgorithm 定义的校验和算法的可用选项:

名称 说明
Auto 0 推荐。 允许库选择算法。 不同的库版本可能会选择不同的算法。
1 没有选定的算法。 不要计算或请求校验和。
MD5 2 标准 MD5 哈希算法。
StorageCrc64 3 Azure 存储自定义 64 位 CRC。

注意

如果请求中指定的校验和与服务计算得出的校验和不匹配,则上传操作将失败。 使用默认重试策略时,不会重试此操作。 在 .NET 中,RequestFailedException 会引发状态代码 400 和错误代码 Md5MismatchCrc64Mismatch,具体取决于使用的是哪种算法。

使用索引标记上传

Blob 索引标记使用键值标记属性对存储帐户中的数据进行分类。 这些标记会自动索引,并作为可搜索的多维索引公开,便于你轻松查找数据。 可以将标记添加到 BlobUploadOptions 实例,并将该实例传递到 UploadAsync 方法中。

以下示例上传设置了索引标记的块 blob:

public static async Task UploadBlobWithTagsAsync(
    BlobContainerClient containerClient,
    string blobName)
{
    BlobClient blobClient = containerClient.GetBlobClient(blobName);
    string blobContents = "Sample blob data";

    BlobUploadOptions options = new BlobUploadOptions();
    options.Tags = new Dictionary<string, string>
    {
        { "Sealed", "false" },
        { "Content", "image" },
        { "Date", "2020-04-20" }
    };

    await blobClient.UploadAsync(BinaryData.FromString(blobContents), options);
}

在上传期间设置 blob 的访问层

可以使用 BlobUploadOptions 类在上传时设置 blob 的访问层。 以下代码示例演示如何在上传 blob 时设置访问层:

public static async Task UploadWithAccessTierAsync(
    BlobContainerClient containerClient,
    string localFilePath)
{
    string fileName = Path.GetFileName(localFilePath);
    BlockBlobClient blockBlobClient = containerClient.GetBlockBlobClient(fileName);

    var uploadOptions = new BlobUploadOptions()
    {
        AccessTier = AccessTier.Cool
    };

    FileStream fileStream = File.OpenRead(localFilePath);
    await blockBlobClient.UploadAsync(fileStream, uploadOptions);
    fileStream.Close();
}

仅允许为块 blob 设置访问层。 可以将块 blob 的访问层设置为 HotCoolColdArchive。 若要将访问层设置为 Cold,必须至少使用客户端库版本 12.15.0。

若要详细了解访问层,请参阅访问层概述

通过暂存块和提交上传块 Blob

可以通过手动暂存单个数据块来更好地控制将上传内容划分为块的方式。 暂存构成 Blob 的所有块后,可以将其提交到 Blob 存储。 可以使用此方法通过并行上传块来提高性能。

public static async Task UploadBlocksAsync(
    BlobContainerClient blobContainerClient,
    string localFilePath,
    int blockSize)
{
    string fileName = Path.GetFileName(localFilePath);
    BlockBlobClient blobClient = blobContainerClient.GetBlockBlobClient(fileName);

    FileStream fileStream = File.OpenRead(localFilePath);
    ArrayList blockIDArrayList = new ArrayList();
    byte[] buffer;

    var bytesLeft = (fileStream.Length - fileStream.Position);

    while (bytesLeft > 0)
    {
        if (bytesLeft >= blockSize)
        {
            buffer = new byte[blockSize];
            await fileStream.ReadAsync(buffer, 0, blockSize);
        }
        else
        {
            buffer = new byte[bytesLeft];
            await fileStream.ReadAsync(buffer, 0, Convert.ToInt32(bytesLeft));
            bytesLeft = (fileStream.Length - fileStream.Position);
        }

        using (var stream = new MemoryStream(buffer))
        {
            string blockID = Convert.ToBase64String(
                Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()));

            blockIDArrayList.Add(blockID);
            await blobClient.StageBlockAsync(blockID, stream);
        }
        bytesLeft = (fileStream.Length - fileStream.Position);
    }

    string[] blockIDArray = (string[])blockIDArrayList.ToArray(typeof(string));

    await blobClient.CommitBlockListAsync(blockIDArray);
}

资源

若要详细了解如何使用适用于 .NET 的 Azure Blob 存储客户端库来上传 Blob,请参阅以下资源。

代码示例

REST API 操作

Azure SDK for .NET 包含基于 Azure REST API 而生成的库,允许你通过熟悉的 .NET 范例与 REST API 操作进行交互。 用于上传 blob 的客户端库方法使用以下 REST API 操作:

另请参阅

  • 本文是适用于 .NET 的 Blob 存储开发人员指南的一部分。 若要了解详细信息,请参阅生成 .NET 应用中的开发人员指南文章的完整列表。