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

如何让Azure WebJob仅下载Azure文件共享中已完整上传的文件?

我碰到过好几个类似的场景,核心问题就是Azure文件共享不会自动标记文件是否处于上传状态,所以WebJob很容易“抢跑”。给你几个实用的解决思路,结合你的代码调整:

解决方案1:用临时文件名标记上传状态

这是最直观的方案——上传端先把文件以临时后缀(比如.tmp)命名,等100%上传完成后,再调用Azure File Share的重命名接口改成正式文件名。WebJob只处理不带临时后缀的文件,从根源上避开未完成的上传文件。

  • 上传端操作:上传大文件时先保存为xxx.ext.tmp,确认上传成功后执行重命名(比如RenameAsync方法)改成xxx.ext
  • WebJob代码调整:修改文件筛选逻辑,只处理正式后缀的文件:
// 只筛选非目录、且不带.tmp后缀的文件
var shareItems = shareDirectory.GetFilesAndDirectories()
    .Where(item => !item.IsDirectory && !item.Name.EndsWith(".tmp", StringComparison.OrdinalIgnoreCase))
    .ToList();
解决方案2:验证文件大小是否稳定

正在上传的文件,其大小会持续变化。我们可以在检测到文件后,先记录当前大小,等待一小段时间(比如10秒)再检查一次,如果两次大小完全一致,说明上传已经完成,再进行下载操作。

调整后的完整代码示例:

var shareItems = shareDirectory.GetFilesAndDirectories().Where(item => !item.IsDirectory).ToList();
foreach (var item in shareItems) {
    ShareFileClient file = shareDirectory.GetFileClient(item.Name);
    if (await file.ExistsAsync()) {
        // 获取初始文件大小
        var initialProps = await file.GetPropertiesAsync();
        long initialSize = initialProps.Value.ContentLength;
        
        // 等待10秒后再次校验大小
        await Task.Delay(TimeSpan.FromSeconds(10));
        
        var updatedProps = await file.GetPropertiesAsync();
        long updatedSize = updatedProps.Value.ContentLength;
        
        // 两次大小一致,判定为上传完成
        if (initialSize == updatedSize) {
            string filePath = Path.Combine(destPath, item.Name);
            using (FileStream stream = File.OpenWrite(filePath)) {
                try {
                    ShareFileDownloadInfo download = await file.DownloadAsync();
                    download.Content.CopyTo(stream);
                } catch (Exception ex) {
                    throw;
                }
                stream.Flush();
                stream.Close();
            }
            // 下载完成后再删除原文件
            await file.DeleteAsync();
        } else {
            // 文件还在上传,跳过本次处理,交给下一轮定时任务
            continue;
        }
    }
}

注意:如果你的上传场景存在暂停再恢复的情况,可以把等待时间拉长,或者增加2-3次大小校验的逻辑,确保准确性。

解决方案3:利用文件锁实现排他访问

这个方案可靠性更高,但需要上传端配合:上传文件时先获取文件的独占锁,上传完成后再释放锁。WebJob尝试获取锁,只有成功拿到锁(说明没有其他进程在写入文件),才执行下载和删除操作。

代码示例:

var shareItems = shareDirectory.GetFilesAndDirectories().Where(item => !item.IsDirectory).ToList();
foreach (var item in shareItems) {
    ShareFileClient file = shareDirectory.GetFileClient(item.Name);
    if (await file.ExistsAsync()) {
        try {
            // 尝试获取5秒超时的独占锁
            var leaseResponse = await file.AcquireLeaseAsync(TimeSpan.FromSeconds(5));
            
            // 成功获取锁,说明文件未被上传进程占用
            string filePath = Path.Combine(destPath, item.Name);
            using (FileStream stream = File.OpenWrite(filePath)) {
                ShareFileDownloadInfo download = await file.DownloadAsync();
                download.Content.CopyTo(stream);
                stream.Flush();
                stream.Close();
            }
            
            // 先释放锁再删除文件
            await file.ReleaseLeaseAsync(leaseResponse.Value.LeaseId);
            await file.DeleteAsync();
        } catch (RequestFailedException ex) {
            // 状态码409表示锁被占用,文件正在上传,直接跳过
            if (ex.Status == (int)HttpStatusCode.Conflict) {
                continue;
            }
            // 其他异常正常抛出
            throw;
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 18:02:41