【问题标题】:Azure Function Blob Trigger copy file to File ShareAzure 函数 Blob 触发器将文件复制到文件共享
【发布时间】:2021-11-11 21:38:06
【问题描述】:

寻求有关如何在使用 Azure 函数 Blob 触发器 (v3) 时将文件从 Azure Blob 存储复制到文件共享的帮助

我看到很多关于从文件共享复制到 Blob 的文章和 SO 问题,但没有任何反向操作,并且尝试反转我发现的代码示例效果不太好

我想出了一个解决方案,但它并不理想,因为我认为它首先将文件下载到内存中,然后将其上传到文件共享:


        [FunctionName("MyBlobTrigger")]
        public async void Run([BlobTrigger("uploads/{name}", Connection = "UploadStorageAccount")]Stream myBlob, string name, ILogger log, CancellationToken cancellationToken)
        {

            ShareClient share = new ShareClient(storageConnection, fileShareName);

            ShareDirectoryClient directory = share.GetRootDirectoryClient();
            ShareFileClient fileShare = directory.GetFileClient(name);

            try
            {
                using (Stream stream = myBlob)
                {
                    fileShare.Create(stream.Length);
                    await fileShare.UploadRangeAsync(new Azure.HttpRange(0, stream.Length), stream);
                }

            }
         }

所以这确实有效,但存在以下问题:

  1. 我认为它是先下载到内存然后上传,宁愿只在 Azure 服务中传输文件,可能会有一些非常大的文件
  2. 我也更喜欢使用 CloudBlockBlob 而不是 Stream 作为我的 blob,主要原因是在函数结束时我需要删除文件,如果使用 CloudBlockBlob,我可以轻松地做到这一点。问题是我在使用它时无法弄清楚如何进行复制

有什么想法吗?

编辑 - 从接受的答案中使用的最终代码:

    [FunctionName("MyBlobTrigger")]
    public async void Run([BlobTrigger("uploads/{name}", Connection = "UploadStorageAccount")]CloudBlockBlob myBlob, string name, ILogger log, CancellationToken cancellationToken)
    {

        ShareClient share = new ShareClient(storageConnection, fileShareName);

        ShareDirectoryClient directory = share.GetRootDirectoryClient();
        ShareFileClient fileShare = directory.GetFileClient(name);

        try
        {

            SharedAccessBlobPolicy sasConstraints = new SharedAccessBlobPolicy
            {
                SharedAccessExpiryTime = DateTime.UtcNow.AddHours(1),
                Permissions = SharedAccessBlobPermissions.Read
            };
            var sasToken = myBlob.GetSharedAccessSignature(sasConstraints);
            var blobSasUrl = $"{myBlob.Uri.AbsoluteUri}{sasToken}";

            fileShare.Create(myBlob.Properties.Length);
            await fileShare.StartCopyAsync(new Uri(blobSasUrl));

【问题讨论】:

  • 根据文档here,您应该能够提供CloudBlockBlob 类型的对象作为输入而不是流。请尝试一下。
  • 是否有任何理由要求您使用 Azure Functions?如果您正在寻找直接的点对点副本,那么 Azure 数据工厂更合适。您可以使用内置的复制数据工具或复制活动 (more info here) 设置具有各种触发器(计划、翻转窗口、存储或自定义 - 更多信息 here)的管道,以非常轻松地实现这一目标。
  • @MattStannett 是的,当文件上传到 Blob 时,我需要运行它作为触发器,在复制操作之前和之后会发生一些我没有显示的处理,然后该文件最终从 blob 中删除,我无法使用数据工厂进行此处理
  • @GauravMantri 是的,我知道我可以使用 CloudBlockBlob 作为触发器输入,这不是我的问题,因为我更愿意使用它,问题是如何将文件从 blob 复制到文件使用 CloudBlockBlob 共享?到目前为止,我只能使用流来做到这一点

标签: c# azure azure-functions azure-blob-storage


【解决方案1】:

要将 blob 的内容复制到文件共享文件,您实际上不需要先下载它。您可以简单地利用 Azure 存储的异步服务器端复制功能。

基本上,您将为具有至少read 权限的 blob 创建一个 SAS URL,然后将其用作文件复制操作的源 URL。

我在下面添加了一些伪代码来展示它是如何完成的。

[FunctionName("MyBlobTrigger")]
public async void Run([BlobTrigger("uploads/{name}", Connection = "UploadStorageAccount")]CloudBlockBlob myBlob, string name, ILogger log, CancellationToken cancellationToken)
{

    //Step 1: Get shared access signature for the blob.
    //var sasToken = myBlob.GetSharedAccessSignature();
    
    //Step 2: Get SAS URL for the blob.
    //var blobSasUrl = $"{myBlob.Uri.AbsoluteUri}{sasToken}";

    ShareClient share = new ShareClient(storageConnection, fileShareName);

    ShareDirectoryClient directory = share.GetRootDirectoryClient();
    ShareFileClient fileShare = directory.GetFileClient(name);

    ShareClient share = new ShareClient(storageConnection, fileShareName);

    ShareDirectoryClient directory = share.GetRootDirectoryClient();
    ShareFileClient fileShare = directory.GetFileClient(name);

    try
    {
        //Step 3: Create empty file based on blob's content length
        //fileShare.Create(myBlob.Properties.Length);
        //Step 4: Copy blob's contents to storage file using async file copy.
        //await fileShare.StartCopyAsync(new Uri(blobSasUrl));
    }
}

【讨论】:

  • 谢谢,我需要为 GetSharedAccessSignature() 添加访问策略,我给它读取、列出、写入、创建 - 只是为了涵盖我的所有基础,但我在复制:“服务器未能对请求进行身份验证。确保授权标头的值格式正确,包括签名。”
  • 我的代码只是一个伪代码。对于复制,您只需要read 权限。从错误来看,您的 SAS 令牌似乎存在问题。您可以编辑您的问题并 1) 包含您的完整代码和 2) 包含您的 SAS 令牌的外观吗?
  • 刚刚发现问题,?构造 blobSasUrl 时不需要,因为它已经是 sas 令牌的一部分,所以我有 ??,删除了额外的,她很好,谢谢!!标记为已回答
  • 感谢您发现问题!我已经编辑了我的答案以删除多余的?
猜你喜欢
  • 2019-08-12
  • 2020-05-13
  • 2018-10-16
  • 2021-06-20
  • 2016-05-29
  • 1970-01-01
  • 2022-01-07
  • 2021-02-22
  • 2021-03-09
相关资源
最近更新 更多