Использование .NET для управления каталогами и файлами в Azure Data Lake Storage

В этой статье показано, как использовать .NET для создания и управления каталогами и файлами в аккаунтах хранения с иерархическим пространством имён (Azure Data Lake Storage 2-го поколения).

Сведения о том, как получить, задать и обновить списки управления доступом (ACL) каталогов и файлов, см. в статье "Использование .NET для управления списками управления доступом" в Azure Data Lake Storage.

Пакет (NuGet) | Примеры | Справочник по API | Сопоставление Gen1 с Gen2 | Отправить отзыв

Предварительные требования

Настройка проекта

Чтобы приступить к работе, установите пакет NuGet Azure.Storage.Files.DataLake.

Дополнительные сведения об установке пакетов NuGet см. в статье Установка пакетов в Visual Studio и управление ими с помощью диспетчера пакетов NuGet.

Затем добавьте эти using инструкции в начало файла с кодом.

using Azure;
using Azure.Storage.Files.DataLake;
using Azure.Storage.Files.DataLake.Models;
using Azure.Storage;
using System.IO;

Примечание.

Многопротокольный доступ к Data Lake Storage позволяет приложениям использовать как API Blob, так и API Data Lake Storage 2-го поколения для работы с данными в учетных записях хранения данных с включенным иерархическим пространством имен (HNS). При работе с возможностями, уникальными для Data Lake Storage 2-го поколения, таких как операции каталогов и списки управления доступом, используйте API Data Lake Storage 2-го поколения, как показано в этой статье.

При выборе API для использования в данном сценарии рассмотрите рабочую нагрузку и потребности приложения, а также известные проблемыи влияние HNS на рабочие нагрузки и приложения.

Авторизация доступа к ресурсам данных и подключение к ним

Для работы с примерами кода в этой статье необходимо создать авторизованный экземпляр DataLakeServiceClient , представляющий учетную запись хранения. Вы можете получить доступ к объекту DataLakeServiceClient с помощью Microsoft Entra ID, ключа доступа к учетной записи или подписи общего доступа (SAS).

Используйте клиентскую библиотеку идентификации Azure для .NET для аутентификации приложения с помощью Microsoft Entra ID.

Создайте экземпляр DataLakeServiceClient и передайте новый экземпляр класса DefaultAzureCredential.

public static DataLakeServiceClient GetDataLakeServiceClient(string accountName)
{
    string dfsUri = $"https://{accountName}.dfs.core.windows.net";

    DataLakeServiceClient dataLakeServiceClient = new DataLakeServiceClient(
        new Uri(dfsUri),
        new DefaultAzureCredential());

    return dataLakeServiceClient;
}

Дополнительные сведения об использовании DefaultAzureCredential для авторизации доступа к данным см. в статье "Проверка подлинности приложений .NET с помощью служб Azure".

Создание контейнера

Контейнер выступает в качестве файловой системы для файлов. Контейнер можно создать с помощью следующего метода:

В следующем примере кода создается контейнер и возвращается объект DataLakeFileSystemClient для последующего использования:

public async Task<DataLakeFileSystemClient> CreateFileSystem(
    DataLakeServiceClient serviceClient,
    string fileSystemName)
{
    return await serviceClient.CreateFileSystemAsync(fileSystemName);
}

После завершения операции контейнер становится доступен в виде файловой системы в аккаунте хранилища.

Создание каталога

Ссылку на каталог в контейнере можно создать с помощью следующего метода:

Следующий пример кода добавляет каталог в контейнер, затем добавляет подкаталог и возвращает объект DataLakeDirectoryClient для последующего использования:

public async Task<DataLakeDirectoryClient> CreateDirectory(
    DataLakeFileSystemClient fileSystemClient,
    string directoryName,
    string subdirectoryName)
{
    DataLakeDirectoryClient directoryClient =
        await fileSystemClient.CreateDirectoryAsync(directoryName);

    return await directoryClient.CreateSubDirectoryAsync(subdirectoryName);
}

Переименование или перемещение каталога

Вы можете переименовать или переместить каталог с помощью следующего метода:

Используя ранее созданный вами параметр DataLakeDirectoryClient , передайте путь каталога в качестве параметра. В следующем примере кода показано, как переименовать подкаталог:

public async Task<DataLakeDirectoryClient> RenameDirectory(
    DataLakeFileSystemClient fileSystemClient,
    string directoryPath,
    string subdirectoryName,
    string subdirectoryNameNew)
{
    DataLakeDirectoryClient directoryClient =
        fileSystemClient.GetDirectoryClient(string.Join('/', directoryPath, subdirectoryName));

    return await directoryClient.RenameAsync(string.Join('/', directoryPath, subdirectoryNameNew));
}

В следующем примере кода показано, как переместить подкаталог из одного каталога в другой каталог:

public async Task<DataLakeDirectoryClient> MoveDirectory(
    DataLakeFileSystemClient fileSystemClient,
    string directoryPathFrom,
    string directoryPathTo,
    string subdirectoryName)
{
    DataLakeDirectoryClient directoryClient =
         fileSystemClient.GetDirectoryClient(string.Join('/', directoryPathFrom, subdirectoryName));

    return await directoryClient.RenameAsync(string.Join('/', directoryPathTo, subdirectoryName));
}

Отправка файла в каталог

Вы можете передать содержимое в новый или существующий файл с помощью следующего метода:

Следующий пример кода использует ранее созданный DataLakeDirectoryClient для отправки локального файла в каталог с помощью метода UploadAsync:

public async Task UploadFile(
    DataLakeDirectoryClient directoryClient,
    string fileName,
    string localPath)
{
    DataLakeFileClient fileClient = 
        directoryClient.GetFileClient(fileName);

    FileStream fileStream = File.OpenRead(localPath);

    DataLakeFileUploadOptions uploadOptions = new()
    {
        // If change notifications are enabled, set Close to true
        // This value indicates the final close of the file stream
        // And emits a change notification event upon successful flush

        // Close = true
    };

    await fileClient.UploadAsync(content: fileStream, options: uploadOptions);
}

После завершения загрузки файл появляется в целевом каталоге с указанным именем.

Добавление данных в файл

Чтобы добавить данные в файл, используйте следующий метод:

В следующем примере кода показано, как добавить данные в конец файла, выполнив следующие действия:

public async Task AppendDataToFile(
    DataLakeDirectoryClient directoryClient,
    string fileName,
    Stream stream)
{
    DataLakeFileClient fileClient = 
        directoryClient.GetFileClient(fileName);

    long fileSize = fileClient.GetProperties().Value.ContentLength;

    await fileClient.AppendAsync(stream, offset: fileSize);

    DataLakeFileFlushOptions flushOptions = new()
    {
        // If change notifications are enabled, set Close to true
        // This value indicates the final close of the file stream
        // And emits a change notification event upon successful flush

        // Close = true
    };

    await fileClient.FlushAsync(position: fileSize + stream.Length, options: flushOptions);
}

Скачивание из каталога

В следующем примере кода показано, как скачать файл из каталога в локальный файл, выполнив следующие действия:

В этом примере для сохранения байтов в файл используются объекты BinaryReader и FileStream.

public async Task DownloadFile(
    DataLakeDirectoryClient directoryClient,
    string fileName,
    string localPath)
{
    DataLakeFileClient fileClient =
        directoryClient.GetFileClient(fileName);

    Response<DataLakeFileReadStreamingResult> downloadResponse = await fileClient.ReadStreamingAsync();

    BinaryReader reader = new BinaryReader(downloadResponse.Value.Content);

    FileStream fileStream = File.OpenWrite(localPath);

    int bufferSize = 4096;

    byte[] buffer = new byte[bufferSize];

    int count;

    while ((count = reader.Read(buffer, 0, buffer.Length)) != 0)
    {
        fileStream.Write(buffer, 0, count);
    }

    await fileStream.FlushAsync();

    fileStream.Close();
}

Вывести содержимое каталога

Вы можете перечислить содержимое каталога с помощью следующего метода и перечисления результата:

Перечисление путей в результате может потребовать выполнения нескольких запросов к службе при получении значений.

Следующий пример кода печатает имена каждого файла, находящегося в каталоге:

public async Task ListFilesInDirectory(
    DataLakeFileSystemClient fileSystemClient,
    string directoryName)
{
    IAsyncEnumerator<PathItem> enumerator =
        fileSystemClient.GetPathsAsync(directoryName).GetAsyncEnumerator();

    await enumerator.MoveNextAsync();

    PathItem item = enumerator.Current;

    while (item != null)
    {
        Console.WriteLine(item.Name);

        if (!await enumerator.MoveNextAsync())
        {
            break;
        }

        item = enumerator.Current;
    }

}

Удаление каталога

Вы можете удалить каталог с помощью следующего метода:

В следующем примере кода показано, как удалить каталог:

public async Task DeleteDirectory(
    DataLakeFileSystemClient fileSystemClient,
    string directoryName)
{
    DataLakeDirectoryClient directoryClient =
        fileSystemClient.GetDirectoryClient(directoryName);

    await directoryClient.DeleteAsync();
}

Восстановление обратимого удаленного каталога

Вы можете использовать клиентские библиотеки служба хранилища Azure, чтобы восстановить каталог, удалённый с возможностью восстановления. Используйте следующий метод для перечисления удаленных путей для экземпляра DataLakeFileSystemClient :

Чтобы восстановить временно удалённый каталог, используйте следующий способ:

В следующем примере кода показано, как получить список удалённых путей и восстановить каталог, помеченный как удалённый:

public async Task RestoreDirectory(
    DataLakeFileSystemClient fileSystemClient,
    string directoryName)
{
    DataLakeDirectoryClient directoryClient =
        fileSystemClient.GetDirectoryClient(directoryName);

    // List deleted paths
    List<PathDeletedItem> deletedItems = new List<PathDeletedItem>();
    await foreach (PathDeletedItem deletedItem in fileSystemClient.GetDeletedPathsAsync(directoryName))
    {
        deletedItems.Add(deletedItem);
    }

    // Restore deleted directory
    Response<DataLakePathClient> restoreResponse = await fileSystemClient.UndeletePathAsync(
        deletedItems[0].Path,
        deletedItems[0].DeletionId);
}

После завершения операции восстановленный справочник и его пути возвращаются на исходное место.

Если переименовать каталог, содержащий обратимо удаленные элементы, эти элементы потеряют связь с каталогом. Если вы хотите восстановить эти элементы, нужно вернуть имя каталога к исходному или создать отдельный каталог с оригинальным именем. В противном случае при попытке восстановить эти обратимо удаленные элементы вы получите сообщение об ошибке.

Создание SAS делегирования пользователей для каталога

Чтобы работать с примерами кода в этом разделе, добавьте следующую using директиву:

using Azure.Storage.Sas;

В следующем примере кода показано, как создать SAS для делегирования пользователей для каталога, если для учетной записи хранения включено иерархическое пространство имен:

async static Task<Uri> GetUserDelegationSasDirectory(DataLakeDirectoryClient directoryClient)
{
    try
    {
        // Get service endpoint from the directory URI.
        DataLakeUriBuilder dataLakeServiceUri = new DataLakeUriBuilder(directoryClient.Uri)
        {
            FileSystemName = null,
            DirectoryOrFilePath = null
        };

        // Get service client.
        DataLakeServiceClient dataLakeServiceClient =
            new DataLakeServiceClient(dataLakeServiceUri.ToUri(),
                                      new DefaultAzureCredential());

        // Get a user delegation key that's valid for seven days.
        // You can use the key to generate any number of shared access signatures 
        // over the lifetime of the key.
        Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey =
            await dataLakeServiceClient.GetUserDelegationKeyAsync(DateTimeOffset.UtcNow,
                                                                  DateTimeOffset.UtcNow.AddDays(7));

        // Create a SAS token that's valid for seven days.
        DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder()
        {
            // Specify the file system name and path, and indicate that
            // the client object points to a directory.
            FileSystemName = directoryClient.FileSystemName,
            Resource = "d",
            IsDirectory = true,
            Path = directoryClient.Path,
            ExpiresOn = DateTimeOffset.UtcNow.AddDays(7)
        };

        // Specify racwl permissions for the SAS.
        sasBuilder.SetPermissions(
            DataLakeSasPermissions.Read |
            DataLakeSasPermissions.Add |
            DataLakeSasPermissions.Create |
            DataLakeSasPermissions.Write |
            DataLakeSasPermissions.List
            );

        // Construct the full URI, including the SAS token.
        DataLakeUriBuilder fullUri = new DataLakeUriBuilder(directoryClient.Uri)
        {
            Sas = sasBuilder.ToSasQueryParameters(userDelegationKey,
                                                  dataLakeServiceClient.AccountName)
        };

        Console.WriteLine("Directory user delegation SAS URI: {0}", fullUri);
        Console.WriteLine();
        return fullUri.ToUri();
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
        throw;
    }
}

В следующем примере выполняется проверка SAS для делегирования пользователя, созданного в предыдущем примере, из имитированного клиентского приложения. Если SAS валиден, клиентское приложение может указать пути к файлам для этой папки. Если SAS недопустим (например, срок действия SAS истек), служба хранилища возвращает код ошибки 403 (запрещено).

private static async Task ListFilesPathsWithDirectorySasAsync(Uri sasUri)
{
    // Try performing an operation using the directory SAS provided.

    // Create a directory client object for listing operations.
    DataLakeDirectoryClient dataLakeDirectoryClient = new DataLakeDirectoryClient(sasUri);

    // List file paths in the directory.
    try
    {
        // Call the listing operation and return pages of the specified size.
        var resultSegment = dataLakeDirectoryClient.GetPathsAsync(false, false).AsPages();

        // Enumerate the file paths returned with each page.
        await foreach (Page<PathItem> pathPage in resultSegment)
        {
            foreach (PathItem pathItem in pathPage.Values)
            {
                Console.WriteLine("File name: {0}", pathItem.Name);
            }
            Console.WriteLine();
        }

        Console.WriteLine();
        Console.WriteLine("Directory listing operation succeeded for SAS {0}", sasUri);
    }
    catch (RequestFailedException e)
    {
        // Check for a 403 (Forbidden) error. If the SAS is invalid, 
        // Azure Storage returns this error.
        if (e.Status == 403)
        {
            Console.WriteLine("Directory listing operation failed for SAS {0}", sasUri);
            Console.WriteLine("Additional error information: " + e.Message);
            Console.WriteLine();
        }
        else
        {
            Console.WriteLine(e.Message);
            Console.ReadLine();
            throw;
        }
    }
}

Дополнительные сведения о создании SAS делегирования пользователей см. в статье "Создание SAS делегирования пользователей с помощью .NET".

Создание SAS службы для каталога

В учетной записи хранения с включённым иерархическим пространством имён можно создать SAS службы для каталога. Чтобы создать SAS службы, убедитесь, что у вас установлен пакет Azure.Storage.Files.DataLake версии 12.5.0 или более поздней.

В следующем примере показано, как создать SAS службы для каталога:

private static Uri GetServiceSasUriForDirectory(DataLakeDirectoryClient directoryClient,
                                          string storedPolicyName = null)
{
    if (directoryClient.CanGenerateSasUri)
    {
        // Create a SAS token that's valid for one hour.
        DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder()
        {
            // Specify the file system name, the path, and indicate that
            // the client object points to a directory.
            FileSystemName = directoryClient.FileSystemName,
            Resource = "d",
            IsDirectory = true,
            Path = directoryClient.Path,
        };

        // If no stored access policy is specified, create the policy
        // by specifying expiry and permissions.
        if (storedPolicyName == null)
        {
            sasBuilder.ExpiresOn = DateTimeOffset.UtcNow.AddHours(1);
            sasBuilder.SetPermissions(DataLakeSasPermissions.Read |
                DataLakeSasPermissions.Write |
                DataLakeSasPermissions.List);
        }
        else
        {
            sasBuilder.Identifier = storedPolicyName;
        }

        // Get the SAS URI for the specified directory.
        Uri sasUri = directoryClient.GenerateSasUri(sasBuilder);
        Console.WriteLine("SAS URI for ADLS directory is: {0}", sasUri);
        Console.WriteLine();

        return sasUri;
    }
    else
    {
        Console.WriteLine(@"DataLakeDirectoryClient must be authorized with Shared Key 
                          credentials to create a service SAS.");
        return null;
    }
}

Дополнительные сведения о создании SAS службы см. в статье "Создание SAS службы с помощью .NET".

См. также