Usare .NET per gestire directory e file in Azure Data Lake Storage

Questo articolo ti mostra come usare .NET per creare e gestire directory e file in account di archiviazione che hanno uno spazio di nomi gerarchico (Azure Data Lake Storage Gen2).

Per informazioni su come ottenere, impostare e aggiornare gli elenchi di controllo di accesso (ACL) di directory e file, vedere Usare .NET per gestire gli elenchi di controllo di accesso in Azure Data Lake Storage.

Pacchetto (NuGet) | Esempi | Riferimento API | Mapping da Gen1 a Gen2 | Fornisci feedback

Prerequisiti

Impostare il progetto

Per iniziare, installare il pacchetto NuGet Azure.Storage.Files.DataLake .

Per altre informazioni su come installare pacchetti NuGet, vedere Installare e gestire i pacchetti in Visual Studio usando il Gestione pacchetti NuGet.

Poi, aggiungi queste using istruzioni in cima al tuo file di codice.

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

Nota

L'accesso multi-protocollo in Data Lake Storage consente alle applicazioni di usare sia le API BLOB che le API Data Lake Storage Gen2 per lavorare con i dati negli account di archiviazione con spazio dei nomi gerarchico (HNS) abilitato. Quando si usano funzionalità specifiche di Data Lake Storage Gen2, ad esempio operazioni di directory e ACL, usare le API data Lake Storage Gen2, come illustrato in questo articolo.

Quando si scelgono le API da usare in uno scenario specifico, prendere in considerazione il carico di lavoro e le esigenze dell'applicazione, insieme ai problemi noti e all'impatto di HNS su carichi di lavoro e applicazioni.

Autorizzare l'accesso e connettersi alle risorse dati

Per usare gli esempi di codice in questo articolo, è necessario creare un'istanza di DataLakeServiceClient autorizzata che rappresenta l'account di archiviazione. È possibile autorizzare un DataLakeServiceClient oggetto usando Microsoft Entra ID, una chiave di accesso all'account o una firma di accesso condiviso.

Usa la libreria client Azure ID per .NET per autenticare la tua applicazione utilizzando Microsoft Entra ID.

Creare un'istanza di DataLakeServiceClient e passare una nuova istanza della classe 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;
}

Per altre informazioni sull'uso DefaultAzureCredential di per autorizzare l'accesso ai dati, vedere Come autenticare le applicazioni .NET con i servizi di Azure.

Creazione di un contenitore

Un contenitore funge da file system per i file. È possibile creare un contenitore usando il metodo seguente:

Nell'esempio di codice seguente viene creato un contenitore e viene restituito un oggetto DataLakeFileSystemClient per un uso successivo:

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

Dopo il completamento dell'operazione, il contenitore è disponibile come file system nell'account di archiviazione.

Crea una directory

È possibile creare un riferimento alla directory nel contenitore usando il metodo seguente:

Il seguente esempio di codice aggiunge una directory a un container, poi aggiunge una sottodirectory e restituisce un oggetto DataLakeDirectoryClient per un uso successivo:

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

    return await directoryClient.CreateSubDirectoryAsync(subdirectoryName);
}

Rinominare o spostare una directory

È possibile rinominare o spostare una directory usando il metodo seguente:

Usando un DataLakeDirectoryClient che hai creato in precedenza, passa il percorso della directory come parametro. L'esempio di codice seguente illustra come rinominare una sottodirectory:

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

Nell'esempio di codice seguente viene illustrato come spostare una sottodirectory da una directory a una directory diversa:

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

Carica un file in una cartella

È possibile caricare contenuto in un file nuovo o esistente usando il metodo seguente:

Il seguente esempio di codice utilizza un DataLakeDirectoryClient creato precedentemente per caricare un file locale in una directory utilizzando il metodo 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);
}

Dopo il completamento del caricamento, il file appare nella cartella di destinazione con il nome specificato.

Accodare dati a un file

Per aggiungere dati a un file, utilizzare il metodo seguente:

Nell'esempio di codice seguente viene illustrato come aggiungere dati alla fine di un file attenendosi alla procedura seguente:

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

Download da una cartella

L'esempio di codice seguente illustra come scaricare un file da una directory in un file locale attenendosi alla procedura seguente:

Questo esempio usa BinaryReader e FileStream per salvare i byte in un file.

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

Elenca i contenuti della directory

È possibile elencare il contenuto della directory usando il metodo seguente ed enumerando il risultato:

L'enumerazione dei percorsi presenti nel risultato potrebbe inviare più richieste al servizio durante il recupero dei valori.

Il seguente esempio di codice stampa i nomi di ogni file che si trova in una directory:

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

}

Eliminare una directory

È possibile eliminare una directory usando il metodo seguente:

Nell'esempio di codice seguente viene illustrato come eliminare una directory:

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

    await directoryClient.DeleteAsync();
}

Ripristinare una directory eliminata temporaneamente

È possibile usare le librerie client di Archiviazione di Azure per ripristinare una directory eliminata temporaneamente. Usare il metodo seguente per elencare i percorsi eliminati per un'istanza di DataLakeFileSystemClient :

Utilizzare il metodo seguente per ripristinare una directory eliminata temporaneamente:

L'esempio di codice seguente mostra come elencare i percorsi eliminati e ripristinare una directory eliminata in modo temporaneo:

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

Al termine dell'operazione, la directory ripristinata e i relativi percorsi tornano nella posizione originale.

Se si rinomina la directory che contiene gli elementi eliminati temporaneamente, tali elementi vengono disconnessi dalla directory. Se vuoi ripristinare quegli elementi, devi riportare il nome della directory al suo nome originale o creare una directory separata che utilizzi il nome originale della directory. In caso contrario, viene visualizzato un errore quando si tenta di ripristinare quegli elementi eliminati temporaneamente.

Creare una firma di accesso condiviso di delega utente per una directory

Per usare gli esempi di codice in questa sezione, aggiungere la direttiva seguente using :

using Azure.Storage.Sas;

L'esempio di codice seguente mostra come generare una SAS di delega utente per una directory quando nell'account di archiviazione è abilitato uno spazio dei nomi gerarchico:

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

L'esempio seguente verifica la SAS di delega utente creata nell'esempio precedente da un'applicazione client simulata. Se il SAS è valido, l'applicazione client può elencare i percorsi dei file per questa directory. Se la firma di accesso condiviso (SAS) non è valida (ad esempio, se è scaduta), il servizio di archiviazione restituisce il codice di errore 403 (Operazione non consentita).

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

Per altre informazioni su come creare una SAS di delega utente, vedere Creare una SAS di delega utente con .NET.

Creare una firma di accesso condiviso del servizio per una directory

In un account di archiviazione con lo spazio dei nomi gerarchico abilitato, è possibile creare una firma di accesso condiviso del servizio per una directory. Per creare il servizio SAS, assicurati di installare la versione 12.5.0 o successiva del pacchetto Azure.Storage.Files.DataLake.

L'esempio seguente mostra come creare una SAS di servizio per una directory:

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

Per altre informazioni su come creare una SAS di servizio, vedi Creare una SAS di servizio con .NET.

Vedi anche