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

Azure Blob Storage调用StartCopyFromUriAsync()偶现零字节文件问题

Azure Media Services 复制到Blob Storage 偶尔出现零字节文件的排查与解决

可能的原因

  • 源URL过期或临时不可访问:Azure Media Services生成的URL通常有有效期,复制过程中URL失效会导致无法读取源数据,最终生成零字节文件。
  • 未检查复制操作状态:仅通过WaitForCompletionAsync返回的结果判断文件大小,忽略了复制失败的情况。
  • 源资产未完全就绪:部分Media Services资产可能还在处理流程中,此时对应的URL无法返回有效数据。

解决方法

1. 复制前验证源URL有效性

在启动复制操作前,先发送HEAD请求确认源文件可访问且非空:

using var httpClient = new HttpClient();
try
{
    var headRequest = new HttpRequestMessage(HttpMethod.Head, url);
    var headResponse = await httpClient.SendAsync(headRequest);
    headResponse.EnsureSuccessStatusCode();
    
    if (headResponse.Content.Headers.ContentLength.HasValue && headResponse.Content.Headers.ContentLength.Value == 0)
    {
        // 源文件为空,记录日志并跳过
        Console.WriteLine($"源文件 {url} 为空,跳过复制");
        return;
    }
}
catch (HttpRequestException ex)
{
    // 源URL不可访问,处理异常
    Console.WriteLine($"验证源URL失败:{ex.Message}");
    throw;
}

2. 检查复制操作的状态与结果

不要直接依赖返回的文件大小,而是检查复制状态,并重新获取Blob属性确认文件大小:

var blob = container.GetBlobClient(fileName);
var operation = await blob.StartCopyFromUriAsync(new Uri(url));
var copyResult = await operation.WaitForCompletionAsync(
    DelayStrategy.CreateExponentialDelayStrategy(
        initialDelay: TimeSpan.FromSeconds(1), maxDelay: TimeSpan.FromMinutes(5)),
    CancellationToken.None);

// 检查复制是否成功
if (copyResult.Value.CopyStatus != CopyStatus.Success)
{
    var errorMsg = $"复制失败:状态={copyResult.Value.CopyStatus},描述={copyResult.Value.CopyStatusDescription}";
    Console.WriteLine(errorMsg);
    throw new InvalidOperationException(errorMsg);
}

// 重新获取Blob属性确认文件大小
var blobProperties = await blob.GetPropertiesAsync();
var fileSize = blobProperties.Value.ContentLength;

if (fileSize == 0)
{
    // 删除无效的零字节文件,可加入重试逻辑
    await blob.DeleteAsync();
    Console.WriteLine($"复制生成零字节文件,已删除:{fileName}");
    // 此处可触发重试
}

3. 添加重试机制

针对临时网络问题或源URL短暂不可用,使用重试策略提升成功率(示例使用Polly库):

using Polly;

// 定义重试策略:针对请求异常或复制失败,重试3次
var retryPolicy = Policy
    .Handle<HttpRequestException>()
    .OrResult<Response<BlobCopyInfo>>(r => r.Value.CopyStatus != CopyStatus.Success)
    .Or<InvalidOperationException>(ex => ex.Message.Contains("零字节文件"))
    .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));

await retryPolicy.ExecuteAsync(async () =>
{
    var blob = container.GetBlobClient(fileName);
    // 先删除可能存在的零字节文件
    await blob.DeleteIfExistsAsync();
    
    var operation = await blob.StartCopyFromUriAsync(new Uri(url));
    var copyResult = await operation.WaitForCompletionAsync(
        DelayStrategy.CreateExponentialDelayStrategy(
            initialDelay: TimeSpan.FromSeconds(1), maxDelay: TimeSpan.FromMinutes(5)),
        CancellationToken.None);

    if (copyResult.Value.CopyStatus != CopyStatus.Success)
    {
        return copyResult;
    }

    var properties = await blob.GetPropertiesAsync();
    if (properties.Value.ContentLength == 0)
    {
        await blob.DeleteAsync();
        throw new InvalidOperationException("复制得到零字节文件");
    }

    return copyResult;
});

4. 确认Media Services资产状态

确保待复制的资产已处理完成,处于可用状态:

// 初始化Media Services客户端
var mediaServicesClient = new AzureMediaServicesClient(new DefaultAzureCredential())
{
    SubscriptionId = "你的订阅ID",
    ResourceGroupName = "资源组名称",
    AccountName = "AMS账户名称"
};

var asset = await mediaServicesClient.Assets.GetAsync("资源组名称", "AMS账户名称", "资产名称");
if (asset.Value.ProvisioningState != AssetProvisioningState.Succeeded)
{
    Console.WriteLine($"资产 {asset.Value.Name} 未就绪,状态:{asset.Value.ProvisioningState}");
    return;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 12:50:54