Uso de .NET para administrar directorios y archivos en Azure Data Lake Storage Gen2

En este artículo se explica cómo usar .NET para crear y administrar directorios y archivos en cuentas de almacenamiento que tengan habilitado un espacio de nombres jerárquico.

Para obtener información sobre cómo obtener, establecer y actualizar las listas de control de acceso (ACL) de directorios y archivos, consulte Uso de .NET para administrar listas de control de acceso en Azure Data Lake Storage Gen2.

Paquete (NuGet) | Ejemplos | Referencia de API | Asignación de Gen1 a Gen2 | Envíenos sus comentarios

Requisitos previos

Configurar su proyecto

Para empezar, instale el paquete NuGet Azure.Storage.Files.DataLake.

Para más información sobre cómo instalar paquetes NuGet, consulte Instalación y administración de paquetes en Visual Studio con el Administrador de paquetes NuGet.

A continuación, agregue estas instrucciones USING al inicio del archivo de código.

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

Nota:

El acceso a varios protocolos en Data Lake Storage permite a las aplicaciones usar las API de blobs y las API de Data Lake Storage Gen2 para trabajar con datos en cuentas de almacenamiento con el espacio de nombres jerárquico (HNS) habilitado. Al trabajar con capacidades exclusivas de Data Lake Storage Gen2, como las operaciones de directorio y las ACL, use las API de Data Lake Storage Gen2, como se muestra en este artículo.

Al elegir qué API usar en un escenario determinado, tenga en cuenta la carga de trabajo y las necesidades de la aplicación, junto con los problemas conocidos y el impacto de HNS en cargas de trabajo y aplicaciones.

Autorización del acceso y conexión a recursos de datos

Para trabajar con los ejemplos de código de este artículo, debe crear una instancia DataLakeServiceClient autorizada que represente la cuenta de almacenamiento. Puede autorizar un objeto DataLakeServiceClient mediante Microsoft Entra ID, una clave de acceso de cuenta o una firma de acceso compartido (SAS).

Puede usar la biblioteca cliente de identidad de Azure para .NET para autenticar la aplicación con Microsoft Entra ID.

Cree una instancia de DataLakeServiceClient y pase una nueva instancia de la clase 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;
}

Para obtener más información sobre el uso de DefaultAzureCredential para autorizar el acceso a los datos, consulte Cómo autenticar aplicaciones .NET con servicios de Azure.

Crear un contenedor

Un contenedor actúa como sistema de archivos para sus archivos. Puede crear un contenedor mediante el método siguiente:

En el siguiente ejemplo se crea un contenedor y se devuelve un objeto DataLakeFileSystemClient para su uso posterior:

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

Creación de un directorio

Puede crear una referencia de directorio en el contenedor mediante el método siguiente:

En el ejemplo de código siguiente se agrega un directorio a un contenedor y, a continuación, se agrega un subdirectorio y se devuelve un objeto DataLakeDirectoryClient para su uso posterior:

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

    return await directoryClient.CreateSubDirectoryAsync(subdirectoryName);
}

Cambio de nombre o traslado de un directorio

Puede cambiar el nombre o mover un directorio mediante el método siguiente:

Pase la ruta de acceso del directorio que busca como un parámetro. En el código de ejemplo siguiente, se muestra cómo cambiar el nombre de un subdirectorio:

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));
}

En el ejemplo de código siguiente se muestra cómo mover un subdirectorio de un directorio a otro:

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));
}

Carga de un archivo en un directorio

Puede cargar contenido en un archivo nuevo o en uno ya existente, mediante el método siguiente:

En el ejemplo de código siguiente se muestra cómo cargar un archivo local en un directorio mediante el método UploadAsync:

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

    FileStream fileStream = File.OpenRead(localPath);

    await fileClient.UploadAsync(content: fileStream, overwrite: true);
}

Puede usar este método para crear y cargar contenido en un archivo nuevo, o bien puede establecer el parámetro overwrite en true para sobrescribir un archivo existente.

Anexión de datos a un archivo

Puede cargar los datos que se van a anexar a un archivo mediante el método siguiente:

En el ejemplo de código siguiente se muestra cómo anexar datos al final de un archivo mediante estos pasos:

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);

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

Descarga de un directorio

En el ejemplo de código siguiente se muestra cómo descargar un archivo de un directorio a un archivo local mediante estos pasos:

  • Cree una instancia de DataLakeFileClient que represente al archivo que quiere descargar.
  • Use el método DataLakeFileClient.ReadAsync y analice el valor devuelto para obtener un objeto Stream. Use cualquier archivo .NET que procese API para guardar bytes de la transmisión en un archivo.

En este ejemplo se usa BinaryReader y FileStream para guardar bytes en un archivo.

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

    Response<FileDownloadInfo> downloadResponse = await fileClient.ReadAsync();

    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();
}

Lista del contenido del directorio

Puede crear una lista del contenido del directorio mediante el método siguiente y enumerar el resultado:

La enumeración de las rutas de acceso en el resultado puede realizar varias solicitudes al servicio mientas captura los valores.

En este código de ejemplo, se imprimen los nombres de cada uno de los archivos que se ubican en un directorio:

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

}

Eliminación de un directorio

Puede eliminar un directorio mediante el método siguiente:

En el código de ejemplo siguiente, se muestra cómo eliminar un directorio:

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

    await directoryClient.DeleteAsync();
}

Restauración de un directorio eliminado temporalmente

Puede usar las bibliotecas cliente de Azure Storage para restaurar un directorio eliminado temporalmente. Use el método siguiente para enumerar las rutas de acceso eliminadas de una instancia de DataLakeFileSystemClient:

Use el método siguiente para restaurar un directorio eliminado temporalmente:

En el ejemplo de código siguiente se muestra cómo enumerar las rutas de acceso eliminadas y restaurar un directorio eliminado temporalmente:

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);
}

Si cambia el nombre del directorio que contiene los elementos eliminados temporalmente, esos elementos se desconectan del directorio. Si desea restaurar esos elementos, tiene que revertir el nombre del directorio al nombre original o crear un directorio independiente que use el nombre del directorio original. De lo contrario, recibe un error al intentar restaurar esos elementos eliminados temporalmente.

Crear una SAS de delegación de usuarios para un directorio

Para trabajar con los ejemplos de código de esta sección, agregue la siguiente directiva de using:

using Azure.Storage.Sas;

En el ejemplo de código siguiente se muestra cómo generar una SAS de delegación de usuarios para un directorio cuando hay un espacio de nombres jerárquico habilitado para la cuenta de almacenamiento:

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

En el ejemplo siguiente se prueba la SAS de delegación de usuarios creada en el ejemplo anterior desde una aplicación cliente simulada. Si la SAS es válida, la aplicación cliente puede mostrar las rutas de acceso de archivo de este directorio. Si la SAS no es válida (por ejemplo, si ha expirado la SAS), el servicio Storage devuelve el código de error 403 (prohibido).

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

Para más información sobre cómo crear una SAS de delegación de usuario, consulte Creación de una SAS de delegación de usuario con .NET.

Creación de una SAS de servicio para un directorio

En una cuenta de almacenamiento con un espacio de nombres jerárquico habilitado, puede crear una SAS de servicio para un directorio. Para crear la SAS de servicio, asegúrese de que ha instalado la versión 12.5.0 o posterior del paquete Azure.Storage.Files.DataLake.

En el ejemplo siguiente se muestra cómo crear una SAS de servicio para un directorio:

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

Para más información sobre cómo crear una SAS de servicio, consulte Creación de una SAS de servicio con .NET.

Consulte también