【问题标题】:Asp.Net Azure Cloud - Getting files size takes long timeAsp.Net Azure Cloud - 获取文件大小需要很长时间
【发布时间】:2020-01-22 07:38:37
【问题描述】:

我想获取父文件夹下可用的各种子文件夹下所有文件的大小总和。

我知道大小,但计算结果大约需要 15 秒。

代码如下:

var storageAccount = CloudStorageAccount.Parse("connectionString");
var fileClient = storageAccount.CreateCloudFileClient();
var cloudFileShare = fileClient.GetShareReference("shareName");
var rootDirectory = cloudFileShare.GetRootDirectoryReference();
var directory = rootDirectory.GetDirectoryReference("folderName");

var size = directory.ListFilesAndDirectories().Select(x => (CloudFileDirectory)x).SelectMany(x => x.ListFilesAndDirectories()).Sum(x => ((CloudFile)x).Properties.Length);

我可以进一步优化它以快速获得大小。

编辑 1:

测试:

  • 场景 1:更多文件夹包含更多或更少文件
  • 场景 2:文件夹更少,文件更多或更少

调查结果:

  • 文件夹数量多时,无论文件如何,都需要很长时间 计数(可能更多或更少)
  • 当文件夹数量较少时,它可以正常工作,而与文件数量无关(可能更多或更少)

【问题讨论】:

    标签: c# .net azure cloud


    【解决方案1】:

    检查您的 LINQ 查询:

    var size = directory
               .ListFilesAndDirectories()
               .Select(x => (CloudFileDirectory)x)
               .SelectMany(x => x.ListFilesAndDirectories())
               .Sum(x => ((CloudFile)x).Properties.Length);
    

    我可以看到一些初始问题。首先,这假设根目录内的第一级仅存在目录。这可以通过铸造(CloudFileDirectory)x 看到。如果找到CloudFile,这将引发异常。一个可扩展的解决方案应该处理这两种类型的文件。其次,此查询还假设每个子目录中仅存在文件,因此 (CloudFile)x 强制转换。这意味着这只会在子目录中深入一层,并且不会通过任何子目录递归。如果找到任何子目录,这也会引发异常。我在下面概述了一些更具可扩展性的方法。

    解决方案 1:

    使用CloudFileDirectory.ListFilesAndDirectories(),它将所有文件组合成一个IEnumerable<IListFileItem>。如果找到文件,则递归遍历每个项目并总结找到的 btyes,如果找到目录,则递归。

    public static void FileShareByteCount(CloudFileDirectory directory, ref long bytesCount)
    {
        if (directory == null)
        {
            throw new ArgumentNullException("directory", "Directory cannot be null");
        }
    
        var files = directory.ListFilesAndDirectories();
    
        foreach (var item in files)
        {
            if (item.GetType() == typeof(CloudFileDirectory))
            {
                var cloudFileDirectory = item as CloudFileDirectory;
                FileShareByteCount(cloudFileDirectory, ref bytesCount);
            }
            else if (item.GetType() == typeof(CloudFile))
            {
                var cloudFile = item as CloudFile;
                bytesCount += cloudFile.Properties.Length;
            }
        }
    }
    

    用法一:

    long bytesCount = 0;
    FileShareByteCount(sampleDir, ref bytesCount);
    Console.WriteLine($"Current file share usage: {bytesCount}");
    

    解决方案 2:

    使用CloudFileDirectory.ListFilesAndDirectoriesSegmented() 分批浏览文件共享,它允许您指定每个IEnumerable<IListFileItem> 段要返回的文件数。同上,递归遍历每一项,如果找到文件则总结找到的btyes,如果找到目录则递归。

    public static void FileShareByteCount(CloudFileDirectory directory, int? maxResults, ref long bytesCount)
    {
        if (directory == null)
        {
            throw new ArgumentNullException("directory", "Directory cannot be null");
        }
    
        FileContinuationToken continuationToken = null;
    
        do
        {
            var resultSegment = directory.ListFilesAndDirectoriesSegmented(maxResults, continuationToken, null, null);
    
            var results = resultSegment.Results;
    
            if (results.Count() > 0)
            {
                foreach (var item in results)
                {
                    if (item.GetType() == typeof(CloudFileDirectory))
                    {
                        var cloudFileDirectory = item as CloudFileDirectory;
                        FileShareByteCount(cloudFileDirectory, maxResults, ref bytesCount);
                    }
                    else if (item.GetType() == typeof(CloudFile))
                    {
                        var cloudFile = item as CloudFile;
                        bytesCount += cloudFile.Properties.Length;
                    }
                }
            }
    
            continuationToken = resultSegment.ContinuationToken;
    
        } while (continuationToken != null);
    }
    

    用法2:

    long bytesCount = 0;
    FileShareByteCount(directory, 100, ref bytesCount);
    Console.WriteLine($"Current file share usage: {bytesCount}");
    

    注意:您可以使用maxResults 指定段的最大大小。微软documentation 声明:

    一个非负整数值,表示一次返回的最大结果数,最多为每次操作的限制 5000。如果此值为 null,则将返回最大可能的结果数,最多到 5000。

    【讨论】:

    • 在上述情况下,此解决方案大约需要 18 秒。 :(
    • @ReyanChougle 嗯,您是否尝试增加/减少 maxResult 的大小?我以100 为例,但这可能不是最好的批量大小。
    • 响应时间也没有改善
    • @ReyanChougle 对不起,我想帮忙。看起来没有其他人回答,所以您原来的 LINQ 查询可能是最好的。唯一的建议是它不是一个非常安全的查询,因为它仅依赖于父目录中存在的子目录。如果directory 中存在任何单独的文件,它将引发异常。这是因为它转换为(CloudFileDirectory)x,但如果CloudFile 存在怎么办?它也可能无法深入很多层,这就是为什么像上面这样的递归解决方案虽然速度较慢,但​​效果很好。
    • 感谢您的宝贵时间,我完全同意您在上面提出的观点。但由于我们的业务需求,我不得不以这种方式编写 LINQ 查询
    猜你喜欢
    • 2012-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-23
    • 1970-01-01
    • 2020-05-02
    • 1970-01-01
    • 2016-08-13
    相关资源
    最近更新 更多