使用 Java 管理 Azure Data Lake Storage 中的目录和文件

本文介绍如何使用 Java 在具有分层命名空间的存储帐户中创建和管理目录与文件。

要了解如何获取、设置和更新目录和文件的访问控制列表 (ACL),请参阅使用 .Java 管理 Azure Data Lake Storage 中的 ACL

包 (Maven) | 示例 | API 参考 | 提供反馈

先决条件

  • Azure 订阅。 有关详细信息,请参阅获取 Azure 试用版

  • 一个已启用分层命名空间的存储帐户。 按这些说明创建一个。

设置项目

若要开始,请打开此页,找到最新版本的 Java 库。 然后,在文本编辑器中打开 pom.xml 文件。 添加引用该版本的依赖项元素。

如果你计划使用 Microsoft Entra ID 来对客户端应用程序进行身份验证,请将依赖项添加到 Azure 标识库。 有关详细信息,请参阅适用于 Java 的 Azure 标识客户端库

接下来,将这些 import 语句添加到代码文件。

import com.azure.identity.*;
import com.azure.storage.common.StorageSharedKeyCredential;
import com.azure.core.http.rest.PagedIterable;
import com.azure.core.util.BinaryData;
import com.azure.storage.file.datalake.*;
import com.azure.storage.file.datalake.models.*;
import com.azure.storage.file.datalake.options.*;

注意

Data Lake Storage 上的多协议访问使应用程序能够同时使用 Blob API 和 Data Lake Storage Gen2 API 来处理启用了分层命名空间 (HNS) 的存储帐户中的数据。 使用 Data Lake Storage Gen2 特有的功能(如目录操作和 ACL)时,请使用 Data Lake Storage Gen2 API,如本文所示。

选择要在给定场景中使用的 API 时,请考虑应用程序的工作负载和需求,以及已知问题HNS 对工作负载和应用程序造成的影响

授权访问并连接到数据资源

若要使用本文中的代码示例,需创建一个表示存储帐户的授权 DataLakeServiceClient 实例。 可以使用 Microsoft Entra ID、帐户访问密钥或共享访问签名 (SAS) 来授权 DataLakeServiceClient 对象。

可以使用适用于 Java 的 Azure 标识客户端库,通过 Microsoft Entra ID 对应用程序进行身份验证。

创建 DataLakeServiceClient 实例并传入 DefaultAzureCredential 类的新实例。

static public DataLakeServiceClient GetDataLakeServiceClient(String accountName){
    DefaultAzureCredential defaultCredential = new DefaultAzureCredentialBuilder().build();

    DataLakeServiceClient dataLakeServiceClient = new DataLakeServiceClientBuilder()
        .endpoint("https://" + accountName + ".dfs.core.chinacloudapi.cn")
        .credential(defaultCredential)
        .buildClient();

    return dataLakeServiceClient;
}

若要详细了解如何使用 DefaultAzureCredential 授权访问数据,请参阅适用于 Java 的 Azure 标识客户端库

创建容器

容器充当文件的文件系统。 可以使用以下方法创建容器:

以下代码示例会创建一个容器,并返回 DataLakeFileSystemClient 对象供以后使用:

public DataLakeFileSystemClient CreateFileSystem(
        DataLakeServiceClient serviceClient,
        String fileSystemName) {

    DataLakeFileSystemClient fileSystemClient = serviceClient.createFileSystem(fileSystemName);

    return fileSystemClient;
}

创建目录

可以使用以下方法在容器中创建目录引用:

下面的代码示例将目录添加到容器,然后添加一个子目录,并返回 DataLakeDirectoryClient 对象供以后使用:

public DataLakeDirectoryClient CreateDirectory(
        DataLakeFileSystemClient fileSystemClient,
        String directoryName,
        String subDirectoryName) {

    DataLakeDirectoryClient directoryClient = fileSystemClient.createDirectory(directoryName);

    return directoryClient.createSubdirectory(subDirectoryName);
}

重命名或移动目录

可以使用以下方法重命名或移动目录:

以参数形式传递所需目录的路径。 以下代码示例说明了如何重命名子目录:

public DataLakeDirectoryClient RenameDirectory(
        DataLakeFileSystemClient fileSystemClient,
        String directoryPath,
        String subdirectoryName,
        String subdirectoryNameNew) {

    DataLakeDirectoryClient directoryClient = fileSystemClient
            .getDirectoryClient(String.join("/", directoryPath, subdirectoryName));

    return directoryClient.rename(
            fileSystemClient.getFileSystemName(),
            String.join("/", directoryPath, subdirectoryNameNew));
}

下面的代码示例演示如何将子目录从一个目录移动到另一个目录:

public DataLakeDirectoryClient MoveDirectory(
        DataLakeFileSystemClient fileSystemClient,
        String directoryPathFrom,
        String directoryPathTo,
        String subdirectoryName) {

    DataLakeDirectoryClient directoryClient = fileSystemClient
            .getDirectoryClient(String.join("/", directoryPathFrom, subdirectoryName));

    return directoryClient.rename(
            fileSystemClient.getFileSystemName(),
            String.join("/", directoryPathTo, subdirectoryName));
}

将文件上传到目录

可以使用以下方法将内容上传到新的或现有的文件:

下面的代码示例演示如何使用 uploadFromFile 方法将本地文件上传到目录:

public void UploadFile(
        DataLakeDirectoryClient directoryClient,
        String fileName) {

    DataLakeFileClient fileClient = directoryClient.getFileClient(fileName);

    fileClient.uploadFromFile("filePath/sample-file.txt");
}

可以使用此方法创建内容并将其上传到新文件,也可以将 overwrite 参数设置为 true,以覆盖现有文件。

将数据追加到文件

可以使用以下方法上传要追加到文件的数据:

下面的代码示例演示如何使用以下步骤将数据追加到文件的末尾:

  • 创建一个 DataLakeFileClient 对象来表示正在使用的文件资源。
  • 使用 DataLakeFileClient.append 方法将数据上传到文件。
  • 通过调用 DataLakeFileClient.flush 方法完成上传,将以前上传的数据写入文件。
public void AppendDataToFile(
        DataLakeDirectoryClient directoryClient) {

    DataLakeFileClient fileClient = directoryClient.getFileClient("sample-file.txt");
    long fileSize = fileClient.getProperties().getFileSize();

    String sampleData = "Data to append to end of file";
    fileClient.append(BinaryData.fromString(sampleData), fileSize);

    fileClient.flush(fileSize + sampleData.length(), true);
}

从目录下载

下面的代码示例演示如何使用以下步骤将文件从目录下载到本地文件:

  • 创建一个 DataLakeFileClient 对象来表示要下载的文件。
  • 使用 DataLakeFileClient.readToFile 方法读取文件。 此示例将 overwrite 参数设置为 true,这将覆盖现有文件。
public void DownloadFile(
        DataLakeDirectoryClient directoryClient,
        String fileName) {

    DataLakeFileClient fileClient = directoryClient.getFileClient(fileName);

    fileClient.readToFile("filePath/sample-file.txt", true);
}

列出目录内容

可以通过使用以下方法并枚举结果来列出目录内容:

枚举结果中的路径可能会在提取值时向服务发出多个请求。

下面的代码示例打印目录中每个文件的名称:

public void ListFilesInDirectory(
        DataLakeFileSystemClient fileSystemClient,
        String directoryName) {

    ListPathsOptions options = new ListPathsOptions();
    options.setPath(directoryName);

    PagedIterable<PathItem> pagedIterable = fileSystemClient.listPaths(options, null);

    java.util.Iterator<PathItem> iterator = pagedIterable.iterator();
    PathItem item = iterator.next();

    while (item != null) {
        System.out.println(item.getName());

        if (!iterator.hasNext()) {
            break;
        }
        item = iterator.next();
    }

}

删除目录

可以使用以下方法之一删除目录:

以下代码示例使用 deleteWithResponse 删除非空目录和目录下的所有路径:

public void DeleteDirectory(
        DataLakeFileSystemClient fileSystemClient,
        String directoryName) {

    DataLakeDirectoryClient directoryClient = fileSystemClient.getDirectoryClient(directoryName);

    // Set to true to delete all paths beneath the directory
    boolean recursive = true;

    directoryClient.deleteWithResponse(recursive, null, null, null);
}

另请参阅