你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

适用于 Java 的 Azure 文件共享客户端库 - 版本 12.20.1

服务器消息块 (SMB) 协议是目前在本地使用的首选文件共享协议。 Microsoft Azure 文件共享服务使客户能够利用 Azure 云基础结构即服务 (IaaS) SMB 的可用性和可伸缩性,而无需重写 SMB 客户端应用程序。

Azure 文件共享服务共享中存储的文件可通过 SMB 协议和 REST API 进行访问。 文件共享服务提供以下四个资源:存储帐户、共享、目录和文件。 共享可用于组织文件集,也可作为云中托管的 SMB 文件共享进行装载。

源代码 | API 参考文档 | REST API 文档 | 产品文档 | 样品

入门

先决条件

添加包

包括 BOM 文件

请将 azure-sdk-bom 包含在项目中,以依赖于库的 GA 版本。 在以下代码段中,将 {bom_version_to_target} 占位符替换为版本号。 若要详细了解 BOM,请参阅 AZURE SDK BOM 自述文件

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.azure</groupId>
            <artifactId>azure-sdk-bom</artifactId>
            <version>{bom_version_to_target}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

然后在没有版本标记的依赖项部分中包含直接依赖项。

<dependencies>
  <dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-storage-file-share</artifactId>
  </dependency>
</dependencies>

包括直接依赖项

如果要依赖于 BOM 中不存在的特定库版本,请将直接依赖项添加到项目,如下所示。

<dependency>
  <groupId>com.azure</groupId>
  <artifactId>azure-storage-file-share</artifactId>
  <version>12.20.1</version>
</dependency>

创建存储帐户

若要创建存储帐户,可以使用 Azure 门户或 Azure CLI

az storage account create \
    --resource-group <resource-group-name> \
    --name <storage-account-name> \
    --location <location>

验证客户端

若要与存储服务 (文件共享服务、共享、目录、MessageId、文件) 需要创建服务客户端类的实例。 为此,需要帐户 SAS (存储帐户字符串) 共享访问签名。 有关详细信息,请参阅 SAS 令牌

获取凭据

  • SAS 令牌

    • 使用以下 Azure CLI 代码片段从存储帐户获取 SAS 令牌。

      az storage file generate-sas
          --name {account name}
          --expiry {date/time to expire SAS token}
          --permission {permission to grant}
          --connection-string {connection string of the storage account}
      
      CONNECTION_STRING=<connection-string>
      
      az storage file generate-sas
          --name javasdksas
          --expiry 2019-06-05
          --permission rpau
          --connection-string $CONNECTION_STRING
      
    • 或者,从 Azure 门户获取帐户 SAS 令牌。

      1. 转到存储帐户。
      2. 单击“共享访问签名”。
      3. 单击“生成 SAS 并连接字符串”。
  • 共享密钥凭据

    • 有两种方法可以创建共享密钥凭据,第一种方法是使用存储帐户名称和帐户密钥。 第二种是使用存储连接字符串。
      1. 使用帐户名称和帐户密钥。
        1. 帐户名称是存储帐户名称。
        2. 转到存储帐户。
        3. 选择“访问密钥”选项卡。
        4. 复制密钥 1 或密钥 2 的“密钥”值。
      2. 使用连接字符串
        1. 转到存储帐户。
        2. 选择“访问密钥”选项卡。
        3. 复制密钥 1 或密钥 2 的“连接字符串”值。

关键概念

URL 格式

文件共享可使用以下 URL 格式进行寻址:

https://<storage account>.file.core.windows.net/<share>

可使用以下 URL 访问示意图中的某个队列:

https://myaccount.file.core.windows.net/images-to-download

资源 URI 语法

对于存储帐户,队列操作的基本 URI 仅包括帐户的名称:

https://myaccount.file.core.windows.net

对于文件,基 URI 包括帐户名称和目录/文件的名称:

https://myaccount.file.core.windows.net/myshare/mydirectorypath/myfile

处理异常

shareServiceClient使用下面的 shareServiceClient 部分生成的 。

try {
    shareServiceClient.createShare("myShare");
} catch (ShareStorageException e) {
    logger.error("Failed to create a share with error code: " + e.getErrorCode());
}

资源名称

用于引用共享、目录或文件的 URI 必须唯一。 在给定的存储帐户中,每个共享均必须具有唯一名称。 给定共享或目录中的每个文件也必须具有在该共享或目录中唯一的名称。

如果你尝试使用违反命名规则的名称创建共享、目录或文件,则请求将失败,状态代码为 400(错误的请求)。

共享名

文件共享服务名称的规则比 SMB 协议针对 SMB 共享名称的规定更加严格,因此 Blob 和文件服务可以共享容器和共享的类似命名约定。 共享的命名限制如下所示:

  1. 共享名必须是有效的 DNS 名称。
  2. 共享名必须以字母或数字开头且只能包含字母、数字和短划线 (-) 字符。
  3. 每个短划线 (-) 字符前后必须紧跟字母或数字;共享名中不允许使用连续划线。
  4. 共享名中的所有字母必须为小写。
  5. 共享名的长度必须为 3 到 63 个字符。

目录和文件名称

目录和文件名的 Azure 文件共享服务命名规则如下所示:

  1. 共享目录和文件名是保留大小写和不区分大小写的。
  2. 共享目录和文件组件名称的长度不能超过 255 个字符。
  3. 共享目录名称不能以 /) (正斜杠字符结尾。 如有,则将自动删除。
  4. 共享文件名不得以正斜杠字符 (/) 结尾。
  5. 必须正确地对保留的 URL 字符进行转义。
  6. 不允许使用以下字符: " \ / : | < > * ?
  7. 不允许使用非法的 URL 路径字符。 像 \uE000 这样的码位虽然在 NTFS 文件名中有效,但不是有效的 Unicode 字符。 此外,也不允许使用某些 ASCII 或 Unicode 字符,如控制字符(0x00 到 0x1F、\u0081 等)。 有关 HTTP/1.1 中管理 Unicode 字符串的规则 ,请参阅 RFC 2616 第 2.2 节:基本规则RFC 3987
  8. 不允许使用以下文件名:LPT1、LPT2、LPT3、LPT4、LPT5、LPT6、LPT7、LPT8、LPT9、COM1、COM2、COM3、COM4、COM5、COM6、COM7、COM8、COM9、PRN、AUX、NUL、CON、CLOCK$、点字符 (.) ,以及两个点字符 (.) 。

元数据名称

共享或文件资源的元数据将存储为与该资源关联的名称值对。 目录不包含元数据。 元数据名称必须遵循 C# 标识符的命名规则。

请注意,元数据名称保留在创建时具有的大小写形式,但在设置或读取时不区分大小写。 如果为资源提交具有同一名称的两个或更多元数据头,则 Azure 文件服务将返回状态代码 400(错误的请求)。

共享服务

文件共享服务 REST API 提供对帐户的操作和管理文件服务属性。 它允许列出和删除共享、获取和设置文件服务属性等操作。 获得 SASToken 后,可以使用 构造 。shareServiceClient${accountName}${sasToken}

String shareServiceURL = String.format("https://%s.file.core.windows.net", ACCOUNT_NAME);
ShareServiceClient shareServiceClient = new ShareServiceClientBuilder().endpoint(shareServiceURL)
    .sasToken(SAS_TOKEN).buildClient();

共享

共享资源包括该共享的元数据和属性。 它允许创建、创建快照、删除共享、获取共享属性、设置元数据、获取和设置 ACL (访问策略) 。 获取和设置 ACL (访问策略) 只能由 ShareClient 和 ConnectionString 使用。

与 SASToken 共享

获得 SASToken 后,可以使用 、、 ${shareName}构造共享客户端${accountName}${sasToken}

String shareURL = String.format("https://%s.file.core.windows.net", ACCOUNT_NAME);
ShareClient shareClient = new ShareClientBuilder().endpoint(shareURL)
    .sasToken(SAS_TOKEN).shareName(shareName).buildClient();

与 ConnectionString 共享

获得 ConnectionString 后,可以使用 、、 ${shareName}构造共享客户端${accountName}${connectionString}

String shareURL = String.format("https://%s.file.core.windows.net", ACCOUNT_NAME);
ShareClient shareClient = new ShareClientBuilder().endpoint(shareURL)
    .connectionString(CONNECTION_STRING).shareName(shareName).buildClient();

共享给 TokenCredential

获得 TokenCredential 后,可以使用 和 ${shareName}ShareTokenIntent构造共享客户端${accountName}ShareTokenIntent.BACKUP 指定用于备份/管理类型操作的请求,这意味着绕过所有文件/目录 ACL 并授予完全权限。 用户必须具有所需的 RBAC 权限才能使用 ShareTokenIntent.BACKUP

String shareURL = String.format("https://%s.file.core.windows.net", ACCOUNT_NAME);

ShareClient serviceClient = new ShareClientBuilder()
    .endpoint(shareURL)
    .credential(tokenCredential)
    .shareTokenIntent(ShareTokenIntent.BACKUP)
    .shareName(shareName)
    .buildClient();

Directory

目录资源包括该目录的属性。 它允许创建、列出、删除目录或子目录或文件、获取属性、设置元数据、列出和强制关闭句柄等操作。 获得 SASToken 后,可以使用 、、${shareName}${directoryPath}、 构造文件服务客户端${accountName}${sasToken}

String directoryURL = String.format("https://%s.file.core.windows.net", ACCOUNT_NAME);
ShareDirectoryClient directoryClient = new ShareFileClientBuilder().endpoint(directoryURL)
    .sasToken(SAS_TOKEN).shareName(shareName).resourcePath(directoryPath).buildDirectoryClient();

文件

文件资源包括该文件的属性。 它允许创建、上传、复制、下载、删除文件或文件范围、获取属性、设置元数据、列出和强制关闭句柄等操作。 获得 SASToken 后,可以使用 、、${shareName}${directoryPath}${fileName}、 构造文件服务客户端${accountName}${sasToken}

String fileURL = String.format("https://%s.file.core.windows.net", ACCOUNT_NAME);
ShareFileClient fileClient = new ShareFileClientBuilder().connectionString(CONNECTION_STRING)
    .endpoint(fileURL).shareName(shareName).resourcePath(directoryPath + "/" + fileName).buildFileClient();

示例

以下部分提供了几个代码片段,涵盖了一些最常见的配置服务任务,包括:

创建共享

在存储帐户中创建共享。 如果无法创建共享,则引发 StorageException。 在 KeyConcept 中获取 ShareServiceClient。 ${shareServiceClient}

String shareName = "testshare";
shareServiceClient.createShare(shareName);

在共享上创建快照

在 KeyConcept 中获取 ShareServiceClient。 ${shareServiceClient}

String shareName = "testshare";
ShareClient shareClient = shareServiceClient.getShareClient(shareName);
shareClient.createSnapshot();

创建目录

采用上面初始化的 shareClient。 ${shareClient}

String dirName = "testdir";
shareClient.createDirectory(dirName);

创建子目录

获取 KeyConcept 中的 directoryClient。 ${directoryClient}

String subDirName = "testsubdir";
directoryClient.createSubdirectory(subDirName);

创建文件

获取 KeyConcept 中的 directoryClient。 ${directoryClient}

String fileName = "testfile";
long maxSize = 1024;
directoryClient.createFile(fileName, maxSize);

列出所有共享

获取 KeyConcept 中的 shareServiceClient, ${shareServiceClient}

shareServiceClient.listShares();

列出所有子目录和文件

获取 KeyConcept 中的 directoryClient, ${directoryClient}

directoryClient.listFilesAndDirectories();

列出文件上的所有区域

获取 KeyConcept 中的 fileClient, ${fileClient}

fileClient.listRanges();

删除共享

获取 KeyConcept 中的 shareClient, ${shareClient}

shareClient.delete();

删除目录

获取 KeyConcept 中的 shareClient。 ${shareClient}

String dirName = "testdir";
shareClient.deleteDirectory(dirName);

删除子目录

获取 KeyConcept 中的 directoryClient。 ${directoryClient}

String subDirName = "testsubdir";
directoryClient.deleteSubdirectory(subDirName);

删除文件

获取 KeyConcept 中的 directoryClient。 ${directoryClient}

String fileName = "testfile";
directoryClient.deleteFile(fileName);

复制文件

获取具有源 URL 字符串的 KeyConcept ${fileClient} 中的 fileClient。

String sourceURL = "https://myaccount.file.core.windows.net/myshare/myfile";
Duration pollInterval = Duration.ofSeconds(2);
SyncPoller<ShareFileCopyInfo, Void> poller = fileClient.beginCopy(sourceURL, (Map<String, String>) null, pollInterval);

中止复制文件

获取 KeyConcept 中的 fileClient, ${fileClient} 上面返回复制 ${copyId}=[copyInfoResponse](#copy-a-file)信息响应。

fileClient.abortCopy("copyId");

将数据上传到存储

获取 KeyConcept 中的 fileClient, ${fileClient} 其数据为“default” 。

String uploadText = "default";
InputStream data = new ByteArrayInputStream(uploadText.getBytes(StandardCharsets.UTF_8));
fileClient.upload(data, uploadText.length());

将大于 4 MB 的数据上传到存储

获取 KeyConcept 中的 fileClient, ${fileClient} 其数据为“default” 。

byte[] data = "Hello, data sample!".getBytes(StandardCharsets.UTF_8);

long chunkSize = 4 * 1024 * 1024L;
if (data.length > chunkSize) {
    for (int offset = 0; offset < data.length; offset += chunkSize) {
        try {
            // the last chunk size is smaller than the others
            chunkSize = Math.min(data.length - offset, chunkSize);

            // select the chunk in the byte array
            byte[] subArray = Arrays.copyOfRange(data, offset, (int) (offset + chunkSize));

            // upload the chunk
            fileClient.uploadWithResponse(new ByteArrayInputStream(subArray), chunkSize, (long) offset, null, Context.NONE);
        } catch (RuntimeException e) {
            logger.error("Failed to upload the file", e);
            if (Boolean.TRUE.equals(fileClient.exists())) {
                fileClient.delete();
            }
            throw e;
        }
    }
} else {
    fileClient.upload(new ByteArrayInputStream(data), data.length);
}

将文件上传到存储

获取 KeyConcept 中的 fileClient。 ${fileClient}

String filePath = "${myLocalFilePath}";
fileClient.uploadFromFile(filePath);

从文件范围下载数据

获取 KeyConcept 中的 fileClient, ${fileClient} 范围从 1024 到 2048。

ShareFileRange fileRange = new ShareFileRange(0L, 2048L);
OutputStream stream = new ByteArrayOutputStream();
fileClient.downloadWithResponse(stream, fileRange, false, null, Context.NONE);

从存储下载文件

获取 KeyConcept 中的 fileClient, ${fileClient} 并下载到 filePath 的文件。

String filePath = "${myLocalFilePath}";
fileClient.downloadToFile(filePath);

获取共享服务属性

在 KeyConcept 中获取 ShareServiceClient。 ${shareServiceClient}

shareServiceClient.getProperties();

设置共享服务属性

在 KeyConcept 中获取 ShareServiceClient。 ${shareServiceClient}

ShareServiceProperties properties = shareServiceClient.getProperties();

properties.getMinuteMetrics().setEnabled(true).setIncludeApis(true);
properties.getHourMetrics().setEnabled(true).setIncludeApis(true);

shareServiceClient.setProperties(properties);

设置共享元数据

获取 KeyConcept 中的 shareClient。 ${shareClient}

Map<String, String> metadata = Collections.singletonMap("directory", "metadata");
shareClient.setMetadata(metadata);

获取共享访问策略

获取 KeyConcept 中的 shareClient。 ${shareClient}

shareClient.getAccessPolicy();

设置共享访问策略

获取 KeyConcept 中的 shareClient。 ${shareClient}

ShareAccessPolicy accessPolicy = new ShareAccessPolicy().setPermissions("r")
    .setStartsOn(OffsetDateTime.now(ZoneOffset.UTC))
    .setExpiresOn(OffsetDateTime.now(ZoneOffset.UTC).plusDays(10));
ShareSignedIdentifier permission = new ShareSignedIdentifier().setId("mypolicy").setAccessPolicy(accessPolicy);
shareClient.setAccessPolicy(Collections.singletonList(permission));

获取目录文件上的句柄

获取 KeyConcept 中的 directoryClient, ${directoryClient}

PagedIterable<HandleItem> handleItems = directoryClient.listHandles(null, true, Duration.ofSeconds(30), Context.NONE);

强制关闭句柄 ID 上的句柄

获取 KeyConcept 中的 directoryClient, ${directoryClient} 并返回上面返回的句柄 ID ${handleId}=[handleItems](#get-handles-on-directory-file)

PagedIterable<HandleItem> handleItems = directoryClient.listHandles(null, true, Duration.ofSeconds(30), Context.NONE);
String handleId = handleItems.iterator().next().getHandleId();
directoryClient.forceCloseHandleWithResponse(handleId, Duration.ofSeconds(30), Context.NONE);

设置共享配额

获取 KeyConcept 中的 shareClient。 ${shareClient}

int quotaOnGB = 1;
shareClient.setPropertiesWithResponse(new ShareSetPropertiesOptions().setQuotaInGb(quotaOnGB), null, Context.NONE);

设置文件 httpheaders

获取 KeyConcept 中的 fileClient。 ${fileClient}

ShareFileHttpHeaders httpHeaders = new ShareFileHttpHeaders().setContentType("text/plain");
fileClient.setProperties(1024, httpHeaders, null, null);

疑难解答

常规

使用此 Java 客户端库与文件交互时,服务返回的错误对应于为 REST API 请求返回的相同 HTTP 状态代码。 例如,如果尝试检索存储帐户中不存在的共享,则会返回错误 404 ,指示 Not Found

默认的 HTTP 客户端

默认情况下,所有客户端库都使用 Netty HTTP 客户端。 添加上述依赖项会自动将客户端库配置为使用 Netty HTTP 客户端。 HTTP 客户端 Wiki 中详述了如何配置或更改 HTTP 客户端。

默认 SSL 库

默认情况下,所有客户端库均使用 Tomcat 原生 Boring SSL 库来为 SSL 操作启用原生级别性能。 Boring SSL 库是一个 uber jar,其中包含适用于 Linux/macOS/Windows 的原生库。与 JDK 内的默认 SSL 实现相比,它提供更好的性能。 有关详细信息(包括如何减小依赖项大小),请参阅 Wiki 的性能优化部分。

后续步骤

贡献

本项目欢迎贡献和建议。 大多数贡献要求你同意贡献者许可协议 (CLA),并声明你有权(并且确实有权)授予我们使用你的贡献的权利。 有关详细信息,请访问 https://cla.microsoft.com

提交拉取请求时,CLA 机器人将自动确定你是否需要提供 CLA,并相应地修饰 PR(例如标签、注释)。 直接按机器人提供的说明操作。 只需使用 CLA 对所有存储库执行一次这样的操作。

此项目采用了 Microsoft 开放源代码行为准则。 有关详细信息,请参阅行为准则常见问题解答,或如果有任何其他问题或意见,请与 联系。

有关参与此存储库的详细信息,请参阅 参与指南

  1. 分叉它
  2. 创建功能分支 (git checkout -b my-new-feature)
  3. () git commit -am 'Add some feature' 提交更改
  4. 推送到分支 (git push origin my-new-feature)
  5. 创建新的拉取请求

曝光数