.NET을 사용하여 Azure Data Lake Storage Gen2에서 디렉터리 및 파일 관리

이 문서에서는 .NET을 사용하여 계층 구조 네임스페이스가 있는 스토리지 계정에서 디렉터리 및 파일을 만들고 관리하는 방법을 보여 줍니다.

디렉터리 및 파일의 ACL(액세스 제어 목록)을 가져오거나 설정하고 업데이트하는 방법에 대한 자세한 내용은 .NET을 사용한 Azure Data Lake Storage Gen2의 ACL 관리를 참조하세요.

패키지(NuGet) | 샘플 | API 참조 | Gen1에서 Gen2로 매핑 | 피드백 제공

필수 구성 요소

  • Azure 구독 Azure 평가판을 참조하세요.

  • 계층 구조 네임스페이스가 사용하도록 설정된 스토리지 계정입니다. 이러한 지침에 따라 라이브러리를 만듭니다.

프로젝트 설정

시작하려면 Azure.Storage.Files.DataLake NuGet 패키지를 설치합니다.

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의 다중 프로토콜 액세스를 통해 애플리케이션은 Blob API와 Data Lake Storage Gen2 API를 모두 사용하여 HNS(계층 구조 네임스페이스)가 사용하도록 설정된 스토리지 계정의 데이터로 작업할 수 있습니다. 디렉터리 작업 및 ACL과 같은 Data Lake Storage Gen2의 고유한 기능을 사용하는 경우 이 문서에 표시된 대로 Data Lake Storage Gen2 API를 사용합니다.

특정 시나리오에서 사용할 API를 선택할 때 알려진 문제HNS가 워크로드 및 애플리케이션에 미치는 영향과 함께 애플리케이션의 워크로드와 요구 사항을 고려합니다.

액세스 권한 부여 및 데이터 리소스에 연결

이 문서의 코드 예제를 사용하려면 스토리지 계정을 나타내는 권한 있는 DataLakeServiceClient 인스턴스를 만들어야 합니다. Microsoft Entra ID, 계정 액세스 키 또는 SAS(공유 액세스 서명)를 사용하여 DataLakeServiceClient 개체에 권한을 부여할 수 있습니다.

.NET용 Azure ID 클라이언트 라이브러리를 사용하여 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을 사용하여 데이터에 대한 액세스 권한을 부여하는 방법에 대한 자세한 내용은 Azure 서비스를 사용하여 .NET 애플리케이션을 인증하는 방법을 참조하세요.

컨테이너 만들기

컨테이너는 파일의 파일 시스템 역할을 합니다. 다음 메서드를 사용하여 컨테이너를 만들 수 있습니다.

다음 코드 예제에서는 컨테이너를 만들고 나중에 사용할 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);
}

디렉터리 이름 바꾸기 또는 이동

다음 메서드를 사용하여 디렉터리의 이름을 바꾸거나 디렉터리를 이동할 수 있습니다.

원하는 디렉터리의 경로를 매개 변수로 전달합니다. 다음 코드 예제에서는 하위 디렉터리의 이름을 바꾸는 방법을 보여 줍니다.

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

디렉터리에 파일 업로드

다음 메서드를 사용하여 새 파일 또는 기존 파일에 콘텐츠를 업로드할 수 있습니다.

다음 코드 예제에서는 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);
}

이 메서드를 사용하여 콘텐츠를 만들고 새 파일에 업로드하거나 overwrite 매개 변수를 true로 설정하여 기존 파일을 덮어쓸 수 있습니다.

파일에 데이터 추가

다음 메서드를 사용하여 파일에 추가할 데이터를 업로드할 수 있습니다.

다음 코드 예제에서는 다음 단계를 사용하여 파일 끝에 데이터를 추가하는 방법을 보여 줍니다.

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

디렉터리에서 다운로드

다음 코드 예제에서는 다음 단계를 사용하여 디렉터리에서 로컬 파일로 파일을 다운로드하는 방법을 보여 줍니다.

  • 다운로드하려는 파일을 나타내는 DataLakeFileClient 인스턴스를 만듭니다.
  • DataLakeFileClient.ReadAsync 메서드를 사용한 다음 반환 값을 구문 분석하여 Stream 개체를 얻습니다. .NET 파일 처리 API를 이용해서 스트림에서 바이트를 파일에 저장합니다.

이 예시에서는 BinaryReaderFileStream을 사용해 바이트를 파일에 저장합니다.

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

디렉터리 콘텐츠 나열

다음 메서드를 사용하고 결과를 열거하여 디렉터리 콘텐츠를 나열할 수 있습니다.

결과의 경로를 열거하면 값을 가져오는 동안 서비스에 여러 요청을 할 수 있습니다.

다음 코드 예제에서는 디렉터리에 있는 각 파일의 이름을 인쇄합니다.

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 Storage 클라이언트 라이브러리를 사용하여 일시 삭제된 디렉터리를 복원할 수 있습니다. 다음 메서드를 사용하여 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가 만료됨) Storage 서비스는 오류 코드 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를 만드는 방법에 대한 자세한 내용은 .NET을 사용하여 사용자 위임 SAS 만들기를 참조하세요.

디렉터리에 대한 서비스 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를 만드는 방법에 대한 자세한 내용은 .NET을 사용하여 서비스 SAS 만들기를 참조하세요.

참고 항목