Asp. Net Azure Облако - получение размера файлов занимает много времени - PullRequest
5 голосов
/ 22 января 2020

Я хочу получить сумму размеров всех файлов в различных дочерних папках, доступных в родительской папке.

Я получаю размер, но для вычисления результатов требуется около 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: меньше папок с большим или меньшим количеством файлов

Выводы:

  • Требуется много времени, когда количество папок больше, независимо от количества файлов (может быть больше или меньше)
  • Работает нормально, когда количество папок меньше, независимо от количества файлов (может быть больше или меньше)

1 Ответ

0 голосов
/ 22 января 2020

Проверка вашего запроса LINQ:

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

Я вижу некоторые начальные проблемы. Во-первых, предполагается, что только каталоги будут существовать на первом уровне внутри каталога root. Это можно увидеть с помощью кастинга (CloudFileDirectory)x. Это вызовет исключение, если вместо этого будет найдено CloudFile. Масштабируемое решение должно обрабатывать оба типа файлов. Во-вторых, этот запрос также предполагает, что в каждом дочернем каталоге будут существовать только файлы, следовательно, приведение (CloudFile)x. Это означает, что это будет только go один уровень глубоко внутри дочерних каталогов, и не будет проходить через любые подкаталоги. Это также вызовет исключение, если вместо этого будут найдены какие-либо подкаталоги. Я изложил некоторые более масштабируемые подходы ниже.

Решение 1:

Используйте CloudFileDirectory.ListFilesAndDirectories(), который объединяет все файлы в IEnumerable<IListFileItem>. Рекурсивно go просматривайте каждый элемент и суммируйте найденные файлы, если файл найден, или рекурсивно, если каталог найден.

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:

Go через файлообмен в пакетном режиме используя CloudFileDirectory.ListFilesAndDirectoriesSegmented(), что позволяет вам указать количество файлов, которые должны быть возвращены на сегмент IEnumerable<IListFileItem>. То же, что и выше, рекурсивно go для каждого элемента и суммирования найденных файлов, если файл найден, или повторное вычисление, если каталог найден.

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. Если это значение равно нулю, будет возвращено максимально возможное количество результатов, вплоть до 5000.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...