You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

编程实现Azure Blob文件夹间文件移动未生效问题

问题根因

代码存在3个直接导致文件移动失败的核心问题:

  • 混淆了Blob容器和虚拟目录的概念:Azure Blob Storage没有实体文件夹结构,你提到的Input/Output/Processed本质是同个容器下Blob名称的路径前缀,属于虚拟目录,不是独立容器。代码中调用GetBlobContainerClient传入文件夹名,实际在尝试访问名称为Input、Processed的不存在的容器,根本没有定位到真实存储的文件。
  • 异步复制未等待完成就删除源文件:StartCopyFromUriAsync仅负责启动复制任务、返回操作句柄,不会等待复制执行完成。代码启动复制后立刻删除源Blob,此时复制任务还在执行中,源文件被删会直接导致复制中断失败。
  • 手动拼接的源Blob URI无访问权限:你拼接的blobUri只有资源路径,没有携带访问凭据,如果存储账户未开启公共匿名访问,服务端执行复制时会因为没有源文件读取权限直接失败。
修复步骤
  1. 先确认你实际存储文件的Blob容器真实名称(绝大多数场景下三个虚拟目录都会归属同一个业务容器,比如命名为workspace、file-store这类),不要把虚拟目录名当成容器名传入。
  2. 调整代码逻辑,使用带凭据的源Blob URI发起复制,等待复制完全完成后再删除源文件。

修复后的参考代码:

private async Task MoveFileAsync(string sourceFolder, string destinationFolder, string fileName, ILogger log)
{
    log.LogInformation("Moving file. Source: {0}  | Destination: {1} | FileName: {2}.", sourceFolder, destinationFolder, fileName);

    try
    {
        var storageConnection = Environment.GetEnvironmentVariable("StorageConnection");
        // 替换为你实际使用的Blob容器名称
        const string actualContainerName = "替换为你的真实容器名";
        
        BlobServiceClient blobServiceClient = new BlobServiceClient(storageConnection);
        BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(actualContainerName);

        // 拼接虚拟目录下的完整Blob路径
        string sourceBlobPath = $"{sourceFolder.TrimEnd('/')}/{fileName}";
        string destBlobPath = $"{destinationFolder.TrimEnd('/')}/{fileName}";

        BlobClient sourceBlob = containerClient.GetBlobClient(sourceBlobPath);
        BlobClient destBlob = containerClient.GetBlobClient(destBlobPath);

        // 直接使用源Blob自带凭据的URI发起复制,无需手动拼接无权限的地址
        CopyFromUriOperation copyOperation = await destBlob.StartCopyFromUriAsync(sourceBlob.Uri);
        // 等待复制任务100%完成
        await copyOperation.WaitForCompletionAsync();

        // 复制完成后再删除源文件
        await sourceBlob.DeleteAsync();
        log.LogInformation("File moved completed, source: {0}, target: {1}", sourceBlobPath, destBlobPath);
    }
    catch (Exception ex)
    {
        log.LogError("Move file failed. {0} | {1} | {2}", ex.Message, ex.StackTrace, ex.InnerException);
        throw; // 不要吞异常,让Function感知失败触发重试
    }
}
补充说明
  • 如果你的三个目录确实是三个独立的Blob容器,也必须保留WaitForCompletionAsync的等待逻辑,同时不要手动拼接无凭据的源URI,直接使用sourceBlob.Uri即可,该URI会自动携带连接字符串对应的访问权限。
  • 如果处理的都是小体积文件,也可以直接用「下载源文件到内存->上传到目标路径->删除源文件」的逻辑替代服务端异步复制,代码逻辑更简单,不需要处理复制状态轮询的问题。

调试截图

内容的提问来源于stack exchange,提问作者Caverman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 10:12:22