一、介绍

通用存储操作common包,支持所有兼容amazon-s3协议的云存储,如minio、oss、cos等,以后客户用啥云储存一套代码都能搞定了,真棒~

二、代码结构

三、代码实现

3.1 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://maven.apache.org/POM/4.0.0"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><artifactId>say-common-oss</artifactId><dependencies><dependency><artifactId>aws-java-sdk-s3</artifactId><groupId>com.amazonaws</groupId><version>${aws.version}</version></dependency><!--大文件分片上传,引入MultipartFile使用,没有大文件分片上传需求,可以删除依赖、删除对应大文件分片上传代码--><dependency><artifactId>spring-web</artifactId><groupId>org.springframework</groupId></dependency><dependency><artifactId>lombok</artifactId><groupId>org.projectlombok</groupId><version>${lombok.version}</version></dependency><dependency><artifactId>spring-boot</artifactId><groupId>org.springframework.boot</groupId></dependency><dependency><artifactId>hutool-all</artifactId><groupId>cn.hutool</groupId><version>${hutool.version}</version></dependency><dependency><artifactId>spring-boot-autoconfigure</artifactId><groupId>org.springframework.boot</groupId></dependency><!--排除springboot-slf4j日志,使用lombok的日志--><dependency><artifactId>spring-boot-starter-logging</artifactId><exclusions><exclusion><artifactId>log4j-to-slf4j</artifactId><groupId>org.apache.logging.log4j</groupId></exclusion><exclusion><artifactId>jul-to-slf4j</artifactId><groupId>org.slf4j</groupId></exclusion></exclusions><groupId>org.springframework.boot</groupId></dependency></dependencies><dependencyManagement><dependencies><dependency><artifactId>spring-boot-dependencies</artifactId><groupId>org.springframework.boot</groupId><scope>import</scope><type>pom</type><version>${spring-boot.version}</version></dependency></dependencies></dependencyManagement><description>aws-s3通用存储操作</description><groupId>com.say.common</groupId><modelVersion>4.0.0</modelVersion><packaging>jar</packaging><properties><aws.version>1.12.470</aws.version><hutool.version>5.8.0</hutool.version><lombok.version>1.18.24</lombok.version><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><spring-boot.version>2.7.7</spring-boot.version></properties><version>1.0.0</version>
</project>

3.2 FileProperties

文件 配置信息 bucket 设置公共读权限

package com.say.common.oss.conf;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;/*** 文件 配置信息 <p> bucket 设置公共读权限** @author zrs*/
@Data
@ConfigurationProperties(prefix = "file")
public class FileProperties {/*** 默认的存储桶名称*/private String bucketName = "test";/*** oss 文件配置信息*/private OssProperties oss;}

3.3 OssProperties

aws 配置信息

package com.say.common.oss.conf;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;/*** aws 配置信息** @author zrs*/
@Data
@Component
@ConfigurationProperties(prefix = "oss")
public class OssProperties {/*** 对象存储服务的URL*/private String endpoint;/*** 自定义域名*/private String customDomain;/*** true path-style nginx 反向代理和S3默认支持 pathStyle {http://endpoint/bucketname} false* <p/>* supports virtual-hosted-style 阿里云等需要配置为 virtual-hosted-style* <p/>* 模式{http://bucketname.endpoint}*/private Boolean pathStyleAccess = true;/*** 应用ID*/private String appId;/*** 区域*/private String region;/*** Access key就像用户ID,可以唯一标识你的账户*/private String accessKey;/*** Secret key是你账户的密码*/private String secretKey;/*** 最大线程数,默认: 100*/private Integer maxConnections = 100;}

3.4 FileTemplate

文件操作模板

package com.say.common.oss.core;import com.amazonaws.services.s3.model.Bucket;
import com.amazonaws.services.s3.model.PutObjectResult;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import com.amazonaws.services.s3.model.S3VersionSummary;
import java.io.InputStream;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.multipart.MultipartFile;/*** 文件操作模板** @author zrs*/
public interface FileTemplate extends InitializingBean {@Overridedefault void afterPropertiesSet() {}/*** 创建bucket** @param bucketName bucket名称*/void createBucket(String bucketName);/*** 获取全部bucket** @return Bucket 列表*/List<Bucket> getAllBuckets();/*** 根据bucket获取bucket详情** @param bucketName bucket名称* @return Optional<Bucket>*/Optional<Bucket> getBucket(String bucketName);/*** @param bucketName bucket名称*/void removeBucket(String bucketName);/*** 上传文件** @param bucketName bucket名称* @param objectName 文件名称* @param stream 文件流* @param contextType 文件类型*/void putObject(String bucketName, String objectName, InputStream stream, String contextType);/*** 上传文件** @param bucketName bucket名称* @param objectName 文件名称* @param stream 文件流* @param size 大小* @param contextType 类型*/PutObjectResult putObject(String bucketName, String objectName, InputStream stream,long size, String contextType);/*** 获取文件信息** @param bucketName bucket名称* @param objectName 文件名称*/S3Object getObjectInfo(String bucketName, String objectName);/*** 上传文件** @param bucketName bucket名称* @param objectName 文件名称* @param stream 文件流*/void putObject(String bucketName, String objectName, InputStream stream);/*** 获取文件** @param bucketName bucket名称* @param objectName 文件名称* @return 二进制流*/S3Object getObject(String bucketName, String objectName);/*** 删除文件** @param bucketName bucketName* @param objectName objectName*/void deleteObject(String bucketName, String objectName);/*** 大文件分段上传** @param file MultipartFile* @param bucketName bucketName* @param objectName objectName* @param minPartSize 每片大小,单位:字节(eg:5242880 <- 5m)*/void uploadMultipartFileByPart(MultipartFile file, String bucketName, String objectName,int minPartSize);/*** 根据文件前置查询文件** @param bucketName bucket名称* @param prefix 前缀* @param recursive 是否递归查询* @return S3ObjectSummary 列表*/List<S3ObjectSummary> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive);/*** 查询文件版本** @param bucketName bucket名称* @return S3ObjectSummary 列表*/List<S3VersionSummary> getAllObjectsVersionsByPrefixV2(String bucketName, String objectName);/*** 获取文件外链** @param bucketName bucket名称* @param objectName 文件名称* @param expires 过期时间 <=7* @return url*/String generatePresignedUrl(String bucketName, String objectName, Integer expires);
}

3.5 OssTemplate

aws-s3 通用存储操作 支持所有兼容s3协议的云存储

package com.say.common.oss.service;import cn.hutool.core.util.ObjectUtil;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.AbortMultipartUploadRequest;
import com.amazonaws.services.s3.model.Bucket;
import com.amazonaws.services.s3.model.CompleteMultipartUploadRequest;
import com.amazonaws.services.s3.model.CompleteMultipartUploadResult;
import com.amazonaws.services.s3.model.InitiateMultipartUploadRequest;
import com.amazonaws.services.s3.model.InitiateMultipartUploadResult;
import com.amazonaws.services.s3.model.ObjectListing;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PartETag;
import com.amazonaws.services.s3.model.PutObjectResult;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import com.amazonaws.services.s3.model.S3VersionSummary;
import com.amazonaws.services.s3.model.UploadPartRequest;
import com.amazonaws.services.s3.model.UploadPartResult;
import com.amazonaws.services.s3.model.VersionListing;
import com.amazonaws.util.IOUtils;
import com.say.common.oss.conf.FileProperties;
import com.say.common.oss.core.FileTemplate;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import lombok.Cleanup;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.multipart.MultipartFile;/*** aws-s3 通用存储操作 支持所有兼容s3协议的云存储** @author zrs*/
@Slf4j
@RequiredArgsConstructor
public class OssTemplate implements InitializingBean, FileTemplate {private final FileProperties properties;private AmazonS3 amazonS3;@Overridepublic void afterPropertiesSet() {ClientConfiguration clientConfiguration = new ClientConfiguration();clientConfiguration.setMaxConnections(properties.getOss().getMaxConnections());AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration(properties.getOss().getEndpoint(), properties.getOss().getRegion());AWSCredentials awsCredentials = new BasicAWSCredentials(properties.getOss().getAccessKey(),properties.getOss().getSecretKey());AWSCredentialsProvider awsCredentialsProvider = new AWSStaticCredentialsProvider(awsCredentials);this.amazonS3 = AmazonS3Client.builder().withEndpointConfiguration(endpointConfiguration).withClientConfiguration(clientConfiguration).withCredentials(awsCredentialsProvider).disableChunkedEncoding().withPathStyleAccessEnabled(properties.getOss().getPathStyleAccess()).build();}/*** 创建bucket** @param bucketName bucket名称* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateBucket">AWS API* Documentation</a>*/@Override@SneakyThrowspublic void createBucket(String bucketName) {// 检验bucket是否存在if (!amazonS3.doesBucketExistV2(bucketName)) {amazonS3.createBucket((bucketName));}}/*** 获取全部bucket* <p>** @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBuckets">AWS* API Documentation</a>*/@Override@SneakyThrowspublic List<Bucket> getAllBuckets() {return amazonS3.listBuckets();}/*** 根据bucket获取bucket详情** @param bucketName bucket名称* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBuckets">AWS* API Documentation</a>*/@Override@SneakyThrowspublic Optional<Bucket> getBucket(String bucketName) {return amazonS3.listBuckets().stream().filter(b -> b.getName().equals(bucketName)).findFirst();}/*** @param bucketName bucket名称* @see <a href=* "http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucket">AWS API* Documentation</a>*/@Override@SneakyThrowspublic void removeBucket(String bucketName) {amazonS3.deleteBucket(bucketName);}/*** 上传文件,指定文件类型** @param bucketName bucket名称* @param objectName 文件名称* @param stream 文件流* @param contextType 文件类型* @throws Exception*/@Override@SneakyThrowspublic void putObject(String bucketName, String objectName, InputStream stream,String contextType) {putObject(bucketName, objectName, stream, stream.available(), contextType);}/*** 上传文件** @param bucketName bucket名称* @param objectName 文件名称* @param stream 文件流* @param size 大小* @param contextType 类型* @throws Exception* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObject">AWS* API Documentation</a>*/@Override@SneakyThrowspublic PutObjectResult putObject(String bucketName, String objectName, InputStream stream,long size, String contextType) {byte[] bytes = IOUtils.toByteArray(stream);ObjectMetadata objectMetadata = new ObjectMetadata();objectMetadata.setContentLength(size);objectMetadata.setContentType(contextType);ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);// 上传return amazonS3.putObject(bucketName, objectName, byteArrayInputStream, objectMetadata);}/*** 获取文件信息** @param bucketName bucket名称* @param objectName 文件名称* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObject">AWS* API Documentation</a>*/@Override@SneakyThrowspublic S3Object getObjectInfo(String bucketName, String objectName) {@CleanupS3Object object = amazonS3.getObject(bucketName, objectName);return object;}/*** 上传文件** @param bucketName bucket名称* @param objectName 文件名称* @param stream 文件流* @throws Exception*/@Override@SneakyThrowspublic void putObject(String bucketName, String objectName, InputStream stream) {putObject(bucketName, objectName, stream, stream.available(), "application/octet-stream");}/*** 获取文件** @param bucketName bucket名称* @param objectName 文件名称* @return 二进制流* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObject">AWS* API Documentation</a>*/@Override@SneakyThrowspublic S3Object getObject(String bucketName, String objectName) {return amazonS3.getObject(bucketName, objectName);}/*** 删除文件** @param bucketName bucket名称* @param objectName 文件名称* @throws Exception* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObject">AWS* API Documentation</a>*/@Override@SneakyThrowspublic void deleteObject(String bucketName, String objectName) {amazonS3.deleteObject(bucketName, objectName);}/*** 大文件分段上传** @param file MultipartFile* @param bucketName bucketName* @param objectName objectName* @param minPartSize 每片大小,单位:字节(eg:5242880 <- 5m)*/@Overridepublic void uploadMultipartFileByPart(MultipartFile file, String bucketName, String objectName,int minPartSize) {if (ObjectUtil.isEmpty(file)) {log.error("file is empty");}// 计算分片大小long size = file.getSize();// 得到总共的段数,和 分段后,每个段的开始上传的字节位置List<Long> positions = Collections.synchronizedList(new ArrayList<>());long filePosition = 0;while (filePosition < size) {positions.add(filePosition);filePosition += Math.min(minPartSize, (size - filePosition));}if (log.isDebugEnabled()) {log.debug("总大小:{},分为{}段", size, positions.size());}// 创建一个列表保存所有分传的 PartETag, 在分段完成后会用到List<PartETag> partETags = Collections.synchronizedList(new ArrayList<>());// 第一步,初始化,声明下面将有一个 Multipart Upload// 设置文件类型ObjectMetadata metadata = new ObjectMetadata();metadata.setContentType(file.getContentType());InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucketName,objectName, metadata);InitiateMultipartUploadResult initResponse = this.initiateMultipartUpload(initRequest);if (log.isDebugEnabled()) {log.debug("开始上传");}//声明线程池ExecutorService exec = Executors.newFixedThreadPool(3);long begin = System.currentTimeMillis();try {// MultipartFile 转 FileFile toFile = multipartFileToFile(file);for (int i = 0; i < positions.size(); i++) {int finalI = i;exec.execute(() -> {long time1 = System.currentTimeMillis();UploadPartRequest uploadRequest = new UploadPartRequest().withBucketName(bucketName).withKey(objectName).withUploadId(initResponse.getUploadId()).withPartNumber(finalI + 1).withFileOffset(positions.get(finalI)).withFile(toFile).withPartSize(Math.min(minPartSize, (size - positions.get(finalI))));// 第二步,上传分段,并把当前段的 PartETag 放到列表中partETags.add(this.uploadPart(uploadRequest).getPartETag());if (log.isDebugEnabled()) {log.debug("第{}段上传耗时:{}", finalI + 1, (System.currentTimeMillis() - time1));}});}//任务结束关闭线程池exec.shutdown();//判断线程池是否结束,不加会直接结束方法while (true) {if (exec.isTerminated()) {break;}}// 第三步,完成上传,合并分段CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest(bucketName,objectName,initResponse.getUploadId(), partETags);this.completeMultipartUpload(compRequest);//删除本地缓存文件if (toFile != null && !toFile.delete()) {log.error("Failed to delete cache file");}} catch (Exception e) {this.abortMultipartUpload(new AbortMultipartUploadRequest(bucketName, objectName,initResponse.getUploadId()));log.error("Failed to upload, " + e.getMessage());}if (log.isDebugEnabled()) {log.debug("总上传耗时:{}", (System.currentTimeMillis() - begin));}}/*** 根据文件前置查询文件集合** @param bucketName bucket名称* @param prefix 前缀* @param recursive 是否递归查询* @return S3ObjectSummary 列表* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjects">AWS* API Documentation</a>*/@Override@SneakyThrowspublic List<S3ObjectSummary> getAllObjectsByPrefix(String bucketName, String prefix,boolean recursive) {ObjectListing objectListing = amazonS3.listObjects(bucketName, prefix);return new ArrayList<>(objectListing.getObjectSummaries());}/*** 查询文件版本** @param bucketName bucket名称* @return S3ObjectSummary 列表* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjects">AWS* API Documentation</a>*/@Override@SneakyThrowspublic List<S3VersionSummary> getAllObjectsVersionsByPrefixV2(String bucketName,String objectName) {VersionListing versionListing = amazonS3.listVersions(bucketName, objectName);return new ArrayList<>(versionListing.getVersionSummaries());}/*** 获取文件外链** @param bucketName bucket名称* @param objectName 文件名称* @param expires 过期时间 <=7* @return url*/@Override@SneakyThrowspublic String generatePresignedUrl(String bucketName, String objectName, Integer expires) {Date date = new Date();Calendar calendar = new GregorianCalendar();calendar.setTime(date);calendar.add(Calendar.DAY_OF_MONTH, expires);URL url = amazonS3.generatePresignedUrl(bucketName, objectName, calendar.getTime());return url.toString();}/*** 初始化,声明有一个Multipart Upload** @param initRequest 初始化请求* @return 初始化返回*/private InitiateMultipartUploadResult initiateMultipartUpload(InitiateMultipartUploadRequest initRequest) {return amazonS3.initiateMultipartUpload(initRequest);}/*** 上传分段** @param uploadRequest 上传请求* @return 上传分段返回* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPart">AWS* API Documentation</a>*/private UploadPartResult uploadPart(UploadPartRequest uploadRequest) {return amazonS3.uploadPart(uploadRequest);}/*** 分段合并** @param compRequest 合并请求* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CompleteMultipartUpload">AWS* API Documentation</a>*/private CompleteMultipartUploadResult completeMultipartUpload(CompleteMultipartUploadRequest compRequest) {return amazonS3.completeMultipartUpload(compRequest);}/*** 中止分片上传** @param uploadRequest 中止文件上传请求* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AbortMultipartUpload">AWS* API Documentation</a>*/private void abortMultipartUpload(AbortMultipartUploadRequest uploadRequest) {amazonS3.abortMultipartUpload(uploadRequest);}/*** MultipartFile 转 File*/private File multipartFileToFile(MultipartFile file) throws Exception {File toFile = null;if (file.equals("") || file.getSize() <= 0) {file = null;} else {InputStream ins = null;ins = file.getInputStream();toFile = new File(file.getOriginalFilename());//获取流文件OutputStream os = new FileOutputStream(toFile);int bytesRead = 0;byte[] buffer = new byte[8192];while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {os.write(buffer, 0, bytesRead);}os.close();ins.close();}return toFile;}}

3.6 OssAutoConfiguration

aws 自动配置类

package com.say.common.oss;import com.say.common.oss.conf.FileProperties;
import com.say.common.oss.service.OssTemplate;
import lombok.AllArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;/*** aws 自动配置类** @author zrs*/
@AllArgsConstructor
@EnableConfigurationProperties({FileProperties.class})
public class OssAutoConfiguration {private final FileProperties properties;@Bean@Primary@ConditionalOnMissingBean(OssTemplate.class)@ConditionalOnProperty(name = "file.oss.enable", havingValue = "true")public OssTemplate ossTemplate() {return new OssTemplate(properties);}}

四、已发布到Gitee,可以直接下载使用

点击进入Gitee,获取代码

五、想了解Minio工具类,MinIO-SDK的方式实现MinIO对象存储操作?

Minio工具类 - Java

手写不易,有用请点赞!

AWS-S3通用存储操作,操作minio、oss、cos等所有兼容s3协议的云存储(含有大文件分片上传实现)相关推荐

  1. minio实现大文件分片上传+断点续传+预览

    minio实现大文件分片上传+断点续传+预览 只提供后端java代码 思路: 前端分片 校验文件md5是否已经存在 --不存在创建临时桶存分片 校验分块是否已经上传 分块上传 合并分块 校验合成后md ...

  2. 文件分片上传阿里云OSS

    本文参考其他博客并结合自身编写 博客原作者:程序猿谢哥哥 博客原地址:https://blog.csdn.net/weixin_42825651/article/details/108792264 注 ...

  3. SpringBoot 分片上传、断点续传、秒传、直传Minio

    最近在学习,在SpringBoot上进行分片上传.断点续传.直接上传到Minio服务器上,中间也遇到的不少坑.自定义minio继承MinioClient来实现分片上传.比较适合初学者. 一.大致的流程 ...

  4. springboot+阿里云OSS分片上传、断点续传、秒传

    最近工作中有使用到OSS的分片上传API,整体流程就是前端将大文件进行分割,每个分片大小是1MB,分片个数是:(文件总大小 / 单个分片大小),前端多线程处理上传分片到后端,后端接收到分片后调用OSS ...

  5. linux 个人云存储_2020年NAS首选,超高速读写备份,联想个人云存储A1深度体验

    写这篇文章之前,我的某马NAS已经吃灰2年,这两年我都是用一个5盘位30TB移动硬盘柜作为日常PC文件的冷备份存储外设,用一个叫做FreeFileSync的软件做为一键同步的工具,详情大家可以查看我早 ...

  6. python分片上传_分片上传_分片上传_上传文件_Python_SDK 示例_对象存储 OSS - 阿里云...

    OSS提供的分片上传(Multipart Upload)功能,将要上传的较大文件(Object)分成多个数据块(Part)来分别上传,上传完成后再调用CompleteMultipartUpload接口 ...

  7. BS文件夹上传操作(二) ——基本功能实现

    上篇<BS文件夹上传操作 >大概说明了我所需要的需求, 接着上次的命题:  "如果有一个需求,要求你在BS上实现文件夹上传操作功能?你该如何实现?" ActiveX?J ...

  8. 软件测试,对于文件的上传下载,导入导出的操作的测试点

    上传下载 1.文件类型 1 .各种常见的文件类型,包括bat, xls, xlsx, doc, exe, jsp, rar, zip, iso等,以及各种视频.音频和图片等. 2.改文件名后缀,例如把 ...

  9. 调用百度网盘开放平台接口,操作百度网盘中的文件,上传、下载等

    1.文件管理 post 文件操作:copy, mover, rename, delete https://pan.baidu.com/rest/2.0/xpan/file? method=filema ...

最新文章

  1. 程序员的爱情 第六章
  2. FPGA之道(28)VHDL的并行语句
  3. python3.7和3.8的区别-Python 3.8 新功能来一波(大部分人都不知道)
  4. python ‘%r‘或者‘{!r}‘的意思
  5. 认识控制台-控制台句柄、附着到控制台、关闭控制台
  6. spring boot中的注解
  7. vb串口 任意波特率_学习串口参数详解:波特率,数据位,停止位,奇偶校验位...
  8. 在Pocket PC/Smartphone智能设备上编写压缩程序(特别简单,任何人都能简单使用)...
  9. sql date 函数_SQL Server DATE函数–终极指南
  10. Android4开发入门经典 之 第四部分:用户界面
  11. pp加速器各种问题官方最新回答
  12. 计算机网络信息安全保密制度,档案馆计算机网络系统和信息安全保密制度
  13. Spring系列技术实战(项目搭建、知识点总结)
  14. 手把手教你十分钟搞定影视类的微信公众号图文排版!
  15. Java相关技术文档汇总
  16. npm link详解
  17. Unity塔防游戏学习(六)
  18. excel 置信区间 计算_Excel 计算置信区间:CONFIDENCE函数详解
  19. Lan9252-FPGA调试笔记
  20. 学生成绩录入系统与查询

热门文章

  1. centos E440 安装无线网卡
  2. 关于PVS-Studio如何在用于... PVS-Studio的库中发现错误的故事
  3. 深入浅出说智图—POW矿池篇
  4. 【清华大学】操作系统 陈渝——Part6 全局页面置换算法
  5. 如何使用Adobe Muse CC 2018 for Mac创建网站?
  6. ww:action用法和给ww:select赋值
  7. 华为平板鸿蒙,鸿蒙OS骁龙870加持 华为MatePad Pro 10.8曝光
  8. zip与unzip一般压缩和带密码压缩与解压缩
  9. VUE element-ui 之table表格第一行插入输入框
  10. 网络流量监控分析工具ntopng的安装与使用