Asp.Net Azure 云 - 获取文件大小需要很长时间



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

我得到了大小,但计算结果大约需要 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:包含更多或更少文件的文件夹更少

发现:

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

检查 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;
}
}
}

用法 1:

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指定段的最大大小。Microsoft文档指出:

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

相关内容

最新更新