diff --git a/.gitignore b/.gitignore index 1a03bac5..12fba5cd 100644 --- a/.gitignore +++ b/.gitignore @@ -24,10 +24,25 @@ hs_err_pid* # maven ignore target/ -.mvn/ bin/ .sts4-cache/ *.versionsBackup +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +# https://github.com/takari/maven-wrapper#usage-without-binary-jar +.mvn/wrapper/maven-wrapper.jar + +# Eclipse m2e generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath # eclipse ignore .settings/ diff --git a/.mvn/jvm.config b/.mvn/jvm.config new file mode 100644 index 00000000..59485b46 --- /dev/null +++ b/.mvn/jvm.config @@ -0,0 +1 @@ +-XX:+UseG1GC -Xmx2g -Xms2g \ No newline at end of file diff --git a/.mvn/maven.config b/.mvn/maven.config new file mode 100644 index 00000000..a8ef5051 --- /dev/null +++ b/.mvn/maven.config @@ -0,0 +1,2 @@ +-s=.mvn/settings.xml +-Dmaven.test.skip=true \ No newline at end of file diff --git a/.mvn/settings.xml b/.mvn/settings.xml new file mode 100644 index 00000000..4e2a6f0a --- /dev/null +++ b/.mvn/settings.xml @@ -0,0 +1,13 @@ + + + + + aliyun + Aliyun Maven Mirror + https://maven.aliyun.com/repository/central + central + + + \ No newline at end of file diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 00000000..b901097f --- /dev/null +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..ffdc10e5 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/.sdkmanrc b/.sdkmanrc new file mode 100644 index 00000000..48aafd15 --- /dev/null +++ b/.sdkmanrc @@ -0,0 +1,4 @@ +# Enable auto-env through the sdkman_auto_env config +# Add key=value pairs of SDKs to use below +maven=3.8.1 +java=8.0.302-open \ No newline at end of file diff --git a/README.md b/README.md index 8e42b26b..e529002d 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@
- + 515706495

@@ -36,7 +36,7 @@ ### 📚简介 一行代码将文件存储到本地、FTP、SFTP、WebDAV、阿里云 OSS、华为云 OBS、七牛云 Kodo、腾讯云 COS、百度云 BOS、又拍云 USS、MinIO、 -Amazon S3、GoogleCloud Storage、金山云 KS3、美团云 MSS、京东云 OSS、天翼云 OOS、移动 云EOS、沃云 OSS、 +Amazon S3、GoogleCloud Storage、FastDFS、 Azure Blob Storage、Cloudflare R2、金山云 KS3、美团云 MSS、京东云 OSS、天翼云 OOS、移动 云EOS、沃云 OSS、 网易数帆 NOS、Ucloud US3、青云 QingStor、平安云 OBS、首云 OSS、IBM COS、其它兼容 S3 协议的存储平台。查看 [所有支持的存储平台](https://x-file-storage.xuyanwu.cn/#/存储平台) 💡 通过 WebDAV 连接到 Alist 后,可以使用百度网盘、天翼云盘、阿里云盘、迅雷网盘等常见存储服务,查看 [Alist 支持的存储平台](https://alist-doc.nn.ci/docs/webdav) @@ -51,6 +51,8 @@ Gitee:https://gitee.com/dromara/x-file-storage 这里是简要的更新记录,查看 [详细的更新记录](https://x-file-storage.xuyanwu.cn/#/更新记录) +`2.1.0` 修复大量问题,新增存储平台 FastDFS 和 Azure Blob Storage,新增复制、移动(重命名)文件,手动分片上传(断点续传)和计算哈希等功能,详情查看 [更新记录](https://x-file-storage.xuyanwu.cn/#/更新记录?id=_210) +
`2.0.0` 捐赠至 [dromara](https://dromara.org/zh) 开源社区,更改项目名、包名,优化项目结构、支持 Metadata 元数据等,从旧版升级需要注意,详情查看 [更新记录](https://x-file-storage.xuyanwu.cn/#/更新记录?id=_200)
`1.0.3` 修复了 FileStorageClientFactory 未自动加载等问题,查看 [更新记录](https://x-file-storage.xuyanwu.cn/#/更新记录?id=_103) @@ -65,11 +67,11 @@ Gitee:https://gitee.com/dromara/x-file-storage ### 📅更新计划 -- 接入存储平台:HDFS、FastDFS、杉岩 OBS、Samba、NFS -- 大文件手动分片上传(1.0.0 已支持大文件自动分片上传) -- 复制或移动文件 +- 接入存储平台:HDFS、火山云 TOS、Samba、NFS +- 用户端直传 +- 追加缩略图 +- 列出文件 - 文件内容预加载 -- 上传无需强制获取 Size - 新增 Access 模块,尝试通过 HTTP、FTP、WebDAV 等协议对外提供接口,方便其它程序使用 ------- @@ -87,7 +89,7 @@ Gitee:https://gitee.com/dromara/x-file-storage org.dromara.x-file-storage x-file-storage-spring - 2.0.0 + 2.1.0 @@ -99,6 +101,8 @@ Gitee:https://gitee.com/dromara/x-file-storage `application.yml` 配置文件中添加以下基础配置 +关于配置文件及 FileInfo 中各种路径(path)的区别,可以参考 [常见问题](https://x-file-storage.xuyanwu.cn/#/常见问题?id=配置文件及-fileinfo-中各种路径(path)的区别?) + ```yaml dromara: x-file-storage: #文件存储配置 @@ -263,6 +267,11 @@ X File Storage 的源码分为两个分支,功能如下: 5. 登录 Gitee 或 Github 在你首页可以看到一个 pull request 按钮,点击它,填写一些说明信息,然后提交即可 6. 等待维护者合并 +#### 🧬 开发约定 & 配置 +1. JDK 11+、Maven 3.8.1+ +2. 代码风格,目前代码风格通过 spotless-maven-plugin + palantir-java-format 统一控制,Maven 构建时统一格式化代码 +3. 在开发阶段,IDE 要识别到 spotless-maven-plugin + palantir-java-format 需要安装插件:[palantir-java-format](https://plugins.jetbrains.com/plugin/13180-palantir-java-format) + #### 📐PR遵照的原则 欢迎任何人为 X File Storage 添砖加瓦,贡献代码,为了易用性和可维护性,需要提交的 pr(pull request)符合一些规范,规范如下: diff --git a/docs/Metadata.md b/docs/Metadata.md index f51fef15..90c0260b 100644 --- a/docs/Metadata.md +++ b/docs/Metadata.md @@ -2,7 +2,7 @@ ## 使用 -可以在上传时传入 Metadata 和 UserMetadata ,目前仅 华为云 OBS、阿里云 OSS、腾讯云 COS、百度云 BOS、七牛云 Kodo、又拍云 USS、MinIO、Amazon S3、GoogleCloud Storage 平台支持 +可以在上传时传入 Metadata 和 UserMetadata ,目前仅 华为云 OBS、阿里云 OSS、腾讯云 COS、百度云 BOS、七牛云 Kodo、又拍云 USS、MinIO、Amazon S3、GoogleCloud Storage、FastDFS、Azure Blob Storage 平台支持 ```java //判断是否支持 Metadata @@ -34,15 +34,30 @@ FileInfo fileInfo = fileStorageService.of(file) ```yaml dromara: x-file-storage: - upload-not-support-metadata-throw-exception: false + upload-not-support-metadata-throw-exception: false # 上传时 + copy-not-support-metadata-throw-exception: false # 复制时 + move-not-support-metadata-throw-exception: false # 移动时 ``` **第二种(仅当前)** ```java +//上传时 FileInfo fileInfo = fileStorageService.of(file) .setNotSupportMetadataThrowException(false) //在不支持 Metadata 的存储平台不抛出异常 .putUserMetadata("role","666") .upload(); + +//复制时 +FileInfo fileInfo = fileStorageService.copy(fileInfo) + .setNotSupportMetadataThrowException(false) //在不支持 Metadata 的存储平台不抛出异常 + .setPlatform("local-plus-1") + .copy(); + +//移动时 +FileInfo fileInfo = fileStorageService.move(fileInfo) + .setNotSupportMetadataThrowException(false) //在不支持 Metadata 的存储平台不抛出异常 + .setPlatform("local-plus-1") + .move(); ``` diff --git a/docs/README.md b/docs/README.md index 65b233fe..a06d28ba 100644 --- a/docs/README.md +++ b/docs/README.md @@ -22,21 +22,22 @@ github star - + star -
- - + + 515706495

+[tg.md](https://x-file-storage.xuyanwu.cn/assets/tg/tg.md ':include') + ------- # 📚简介 一行代码将文件存储到本地、FTP、SFTP、WebDAV、阿里云 OSS、华为云 OBS、七牛云 Kodo、腾讯云 COS、百度云 BOS、又拍云 USS、MinIO、 -Amazon S3、GoogleCloud Storage、金山云 KS3、美团云 MSS、京东云 OSS、天翼云 OOS、移动 云EOS、沃云 OSS、 +Amazon S3、GoogleCloud Storage、FastDFS、 Azure Blob Storage、Cloudflare R2、金山云 KS3、美团云 MSS、京东云 OSS、天翼云 OOS、移动 云EOS、沃云 OSS、 网易数帆 NOS、Ucloud US3、青云 QingStor、平安云 OBS、首云 OSS、IBM COS、其它兼容 S3 协议的存储平台。查看 [所有支持的存储平台](存储平台) 💡 通过 WebDAV 连接到 Alist 后,可以使用百度网盘、天翼云盘、阿里云盘、迅雷网盘等常见存储服务,查看 [Alist 支持的存储平台](https://alist-doc.nn.ci/docs/webdav) @@ -51,6 +52,8 @@ Gitee:https://gitee.com/dromara/x-file-storage 这里是简要的更新记录,查看 [详细的更新记录](更新记录) +`2.1.0` 修复大量问题,新增存储平台 FastDFS 和 Azure Blob Storage,新增复制、移动(重命名)文件,手动分片上传(断点续传)和计算哈希等功能,详情查看 [更新记录](更新记录?id=_210) +
`2.0.0` 捐赠至 [dromara](https://dromara.org/zh) 开源社区,更改项目名、包名,优化项目结构、支持 Metadata 元数据等,从旧版升级需要注意,详情查看 [更新记录](更新记录?id=_200)
`1.0.3` 修复了 FileStorageClientFactory 未自动加载等问题,查看 [更新记录](更新记录?id=_103) @@ -65,11 +68,11 @@ Gitee:https://gitee.com/dromara/x-file-storage # 📅更新计划 -- 接入存储平台:HDFS、FastDFS、杉岩 OBS、Samba、NFS -- 大文件手动分片上传(1.0.0 已支持大文件自动分片上传) -- 复制或移动文件 +- 接入存储平台:HDFS、火山云 TOS、Samba、NFS +- 用户端直传 +- 追加缩略图 +- 列出文件 - 文件内容预加载 -- 上传无需强制获取 Size - 新增 Access 模块,尝试通过 HTTP、FTP、WebDAV 等协议对外提供接口,方便其它程序使用 ------- @@ -288,6 +291,15 @@ X File Storage 感谢各位小伙伴的信任与支持,如果您已经在项 x-file-storage + + WeMQAQ + + + Mayfly-Go + + + Akali + dromara diff --git a/docs/_navbar.md b/docs/_navbar.md index 1367826f..42a7ab40 100644 --- a/docs/_navbar.md +++ b/docs/_navbar.md @@ -1,5 +1,6 @@ -* 🌟文档版本 2.0.0 +* 🌟文档版本 2.1.0 + * [2.1.0](https://x-file-storage.xuyanwu.cn/2.1.0/) * [2.0.0](https://x-file-storage.xuyanwu.cn/2.0.0/) * [1.0.3](https://x-file-storage.xuyanwu.cn/1.0.3/) * [1.0.2](https://x-file-storage.xuyanwu.cn/1.0.2/) diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 2677c2c2..5ddd343f 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -7,6 +7,7 @@ * [🥦存储平台](存储平台 "存储平台") * [🌽文件适配器](文件适配器 "文件适配器") * [🔍️识别文件的 MIME 类型](识别文件的MIME类型 "识别文件的 MIME 类型") +* [🍵️计算哈希](hash "hash") * [🧪切面](切面 "切面") * [🌱脱离 SpringBoot 单独使用](脱离SpringBoot单独使用 "脱离 SpringBoot 单独使用") * [🙋‍♂️常见问题](常见问题 "常见问题") diff --git a/docs/acl.md b/docs/acl.md index e125c0fc..61297b93 100644 --- a/docs/acl.md +++ b/docs/acl.md @@ -1,6 +1,8 @@ # ACL 访问控制列表 -也叫预定义访问策略,目前仅 华为云 OBS、阿里云 OSS、腾讯云 COS、百度云 BOS、Amazon S3、GoogleCloud Storage 平台支持 +也叫预定义访问策略,目前仅 华为云 OBS、阿里云 OSS、腾讯云 COS、百度云 BOS、Amazon S3、GoogleCloud Storage、Azure Blob Storage 平台支持 + +Azure Blob Storage 即使将文件的 ACL 设置为 公共读`PUBLIC_READ` ,上传成功后的 `url` 也无法通过浏览器直接公开访问 ,详情阅读 [兼容性说明-AzureBlobStorage](存储平台?id=OCI_AzureBlobStorage) 章节 ## 设置 ACL @@ -109,6 +111,27 @@ fileStorageService.of(file).setFileAcl(Arrays.asList(acl2,acl3)).upload(); ``` +#### **Azure Blob Storage** + +ACL 参考文档:https://learn.microsoft.com/zh-cn/azure/storage/blobs/data-lake-storage-access-control
+SDK 参考文档:https://learn.microsoft.com/zh-cn/azure/storage/blobs/data-lake-storage-acl-java#set-acls + +```java +//第一种:使用官方 SDK 中的 PathPermissions 对象 +PathPermissions permissions = new PathPermissions() + .setGroup(new RolePermissions().setReadPermission(true)) + .setOwner(new RolePermissions().setReadPermission(true).setWritePermission(true)); +fileStorageService.of(file).setFileAcl(permissions).upload(); + +//第二种,使用官方 SDK 中的 PathAccessControlEntry 对象 +PathAccessControlEntry acl = PathAccessControlEntry.parse("user::rw-"); +fileStorageService.of(file).setFileAcl(acl).upload(); + +//第二种可以一次设置多个 +List acl = PathAccessControlEntry.parseList("user::rw-,group::r--,other::---"); +fileStorageService.of(file).setFileAcl(acl).upload(); +``` + > [!WARNING|label:重要提示:] @@ -142,13 +165,28 @@ AccessControlList acl = client.getObjectAcl(fileStorage.getBucketName(),fileStor ```yaml dromara: x-file-storage: - upload-not-support-alc-throw-exception: false + upload-not-support-alc-throw-exception: false # 上传时 + copy-not-support-alc-throw-exception: false # 复制时 + move-not-support-alc-throw-exception: false # 移动时 ``` **第二种(仅当前)** ```java +//上传时 FileInfo fileInfo = fileStorageService.of(file) .setNotSupportAclThrowException(false) //在不支持 ACL 的存储平台不抛出异常 .setAcl(Constant.ACL.PRIVATE) .upload(); + +//复制时 +FileInfo fileInfo = fileStorageService.copy(fileInfo) + .setNotSupportAclThrowException(false) //在不支持 ACL 的存储平台不抛出异常 + .setPlatform("local-plus-1") + .copy(); + +//移动时 +FileInfo fileInfo = fileStorageService.move(fileInfo) + .setNotSupportAclThrowException(false) //在不支持 ACL 的存储平台不抛出异常 + .setPlatform("local-plus-1") + .move(); ``` diff --git a/docs/hash.md b/docs/hash.md new file mode 100644 index 00000000..d0916e7f --- /dev/null +++ b/docs/hash.md @@ -0,0 +1,100 @@ +# 计算哈希 + +可以在上传、下载的同时计算文件的哈希值,例如 `MD5` `SHA256` 等,更多哈希以实际 API 为准 + +### 直接上传文件时 + +```java +FileInfo fileInfo = fileStorageService.of(file) + .setHashCalculatorMd5() //计算 MD5 + .setHashCalculatorSha256() //计算 SHA256 + .setHashCalculator(Constant.Hash.MessageDigest.MD2) //指定哈希名称,这里定义了一些常用的哈希名称 + .setHashCalculator("SHA-512") //指定哈希名称,内部是通过 MessageDigest 来计算哈希值的,只要是 MessageDigest 支持的名称就都可以 + .setHashCalculator(MessageDigest.getInstance("SHA-384")) //指定 MessageDigest + .upload(); + +//上传成功后即可这样获取到对应的哈希值 +HashInfo hashInfo = fileInfo.getHashInfo(); +String md5 = hashInfo.getMd5(); +String sha256 = hashInfo.getSha256(); +``` + +### 手动分片上传-上传分片时 + +注意,在上传到本地、又拍云 USS 等存储平台时,会自动调用 setHashCalculatorMd5() 方法计算 MD5 作为分片的 etag 值,其它存储平台不会 + +```java +FilePartInfo filePartInfo = fileStorageService.uploadPart(fileInfo, partNumber, bytes, (long) bytes.length) + .setHashCalculatorMd5() //计算 MD5 + .setHashCalculatorSha256() //计算 SHA256 + .setHashCalculator(Constant.Hash.MessageDigest.MD2) //指定哈希名称,这里定义了一些常用的哈希名称 + .setHashCalculator("SHA-512") //指定哈希名称,内部是通过 MessageDigest 来计算哈希值的,只要是 MessageDigest 支持的名称就都可以 + .setHashCalculator(MessageDigest.getInstance("SHA-384")) //指定 MessageDigest + .upload(); + +//上传成功后即可这样获取到对应的哈希值 +HashInfo hashInfo = filePartInfo.getHashInfo(); +String md5 = hashInfo.getMd5(); +String sha256 = hashInfo.getSha256(); +``` + +### 下载时 + +```java +Downloader downloader = fileStorageService.downloadTh(fileInfo) + .setHashCalculatorMd5() //计算 MD5 + .setHashCalculatorSha256() //计算 SHA256 + .setHashCalculator(Constant.Hash.MessageDigest.MD2) //指定哈希名称,这里定义了一些常用的哈希名称 + .setHashCalculator("SHA-512") //指定哈希名称,内部是通过 MessageDigest 来计算哈希值的,只要是 MessageDigest 支持的名称就都可以 + .setHashCalculator(MessageDigest.getInstance("SHA-384")); //指定 MessageDigest + +//下载为 byte[] +byte[] thBytes = downloader.bytes(); + +//下载成功后即可这样获取到对应的哈希值 +HashInfo hashInfo = downloader.getHashCalculatorManager().getHashInfo(); +String md5 = hashInfo.getMd5(); +String sha256 = hashInfo.getSha256(); +``` + +### 自定义计算哈希 + +只需要实现 `HashCalculator` 接口即可,这里用 `MD5` 举例 + +```java +FileInfo fileInfo = fileStorageService.of(file) + .setHashCalculator(new HashCalculator() { + private final MessageDigest messageDigest = MessageDigest.getInstance("MD5"); + + /** + * 获取哈希名称,例如 MD5、SHA1、SHA256等 + */ + @Override + public String getName() { + return messageDigest.getAlgorithm(); + } + + /** + * 获取哈希值,一般情况下获取后将不能继续增量计算哈希 + */ + @Override + public String getValue() { + return HexUtil.encodeHexStr(messageDigest.digest()); + } + + /** + * 增量计算哈希 + * @param bytes 字节数组 + */ + @Override + public void update(byte[] bytes) { + messageDigest.update(bytes); + } + }) + .upload(); + +//上传成功后即可这样获取到对应的哈希值 +HashInfo hashInfo = fileInfo.getHashInfo(); +String md5 = hashInfo.get("MD5"); +``` + diff --git a/docs/index.html b/docs/index.html index a33875dd..07fafca5 100644 --- a/docs/index.html +++ b/docs/index.html @@ -7,8 +7,8 @@ - +