S3对象存储上传文件夹
背景:Amazon S3提供了方便易用的对象存储接口,在对象存储中数据是以key-value的形式存放,对象之间默认没什么关联。在实际应用场景中,我们可能需要将一个文件夹上传到S3中,而不是一个一个文件地上传,并且期望保留文件夹里文件的层级关系。本文介绍三种方法,第三种用代码是重点。1.使用S3Browser在S3的客户端S3Browser中,我们发现可以upload floder,我将本地 H:
背景:Amazon S3提供了方便易用的对象存储接口,在对象存储中数据是以key-value的形式存放,对象之间默认没什么关联。在实际应用场景中,我们可能需要将一个文件夹上传到S3中,而不是一个一个文件地上传,并且期望保留文件夹里文件的层级关系。本文介绍三种方法,第三种用代码是重点。
1.使用S3Browser
在S3的客户端S3Browser中,我们发现可以upload floder,我将本地 H:\video\test 文件夹上传,test文件夹里有1.txt,2.txt两个文件和一个名为test2的文件夹,test2里有3.txt一个文件。使用S3Browser的upload floder将此文件夹上传后,可以看到图中效果:
结果是符合我们预期的。
2.使用s3cmd
用命令行查看上面操作的效果,发现Data这个bucket里多了一个/test/
我们再查看Data/test,可以看到test里有test2和两个对象1.txt,2.txt,也达到了预期。
实际上S3有上传文件夹命令:
s3cmd put -r yourfloder s3://yourbucket
比如 s3cmd put -r ceph-cluster s3://Data,把ceph-cluster上传:
3.使用API
尽管我们看到的上传文件夹后,在S3 bucket里有类似目录的东西,但是这并不是文件系统里那样的目录,只是S3用来表示层级关系的一种方式,在S3Browser中以图形界面的方式表现出来,并不是真正的我们常说的文件夹。
它只是通过 / 这个符号来表示层级关系
在S3提供的API中,并没有上传文件夹相关的方法,只有上传单个文件作为对象,源码接口如下:
PutObjectResult putObject(PutObjectRequest var1) throws SdkClientException, AmazonServiceException;
PutObjectResult putObject(String var1, String var2, File var3) throws SdkClientException, AmazonServiceException;
PutObjectResult putObject(String var1, String var2, InputStream var3, ObjectMetadata var4) throws SdkClientException, AmazonServiceException;
PutObjectResult putObject(String var1, String var2, String var3) throws AmazonServiceException, SdkClientException;
所以如果我们想通过代码上传文件夹,必须基于putObject()这个方法来写。
综上所述,要自己写代码上传文件夹,就要用 / 体现层次关系。所以这个问题转化成了——我们要获取子文件夹里的文件相对于父亲文件夹的路径,举个例子:我们要上传 *H:\video\test* 文件夹,其中的H:\video\test\test2\3.txt这个文件相对于H:\video\test\的路径表示就是\test\test2\3.txt。
代码的思路是:
- 输入文件夹路径,读取文件夹里文件,判断是文件还是子文件夹,如果是文件则记录其路径
- 如果是子文件夹,递归调用上面方法
- 对路径格式进行处理,转换成我们想要的格式,放在一个map里;注意开头不能带 /,否则S3里会出现名为 / 的文件夹
import s3service.S3ServiceImpl;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @ClassName: FloderUpload
* @Description: TODO
* @Author: PallasCat
* @Version: V1.0
* @Data: 2020/12/9 10:59
**/
public class FloderUpload {
static Map<String,String> flieMap = new HashMap<>();
public static void main(String[] args) throws IOException {
String path = "H:\\video\\test";
String bucketName = "Data";
uploadFloder(path,bucketName);
}
public static void uploadFloder(String floderPath, String bucketName) throws IOException {
S3ServiceImpl s3Service=new S3ServiceImpl();
s3Service.createConnect();
String path = floderPath;
String iniPath = new File(path).getParent()+File.separator;
listAllFile(iniPath, path, flieMap);
for(String absolutePath : flieMap.keySet()){
System.out.println(absolutePath);
System.out.println(flieMap.get(absolutePath));
//s3Service是我自己根据官方接口putObject写的高层API
s3Service.createObject(bucketName, flieMap.get(absolutePath), new File(absolutePath) );
}
}
public static Map<String,String> listAllFile(String iniPath , String filePath, Map<String,String> flieMap) throws IOException {
if(!filePath.endsWith(File.separator)){
filePath = filePath + File.separator;
}
File file = new File(filePath);
if(file.isDirectory()){
File[] files = file.listFiles();
for (File fileIndex : files){
if(fileIndex.isDirectory()){
listAllFile(iniPath,fileIndex.getPath()+File.separator, flieMap);
}
else{
String aa = fileIndex.getPath();
String bb = file.getParent()+File.separator;
String cc = aa.replace(iniPath,"");
//Windows路径用\分割,Linux用/分割,所以需要转换
String dd = cc.replace("\\", "/");
//map的key是文件绝对路径,value是转换后的格式,用于S3对象名,可创造目录结构
flieMap.put(aa,dd);
}
}
}
return flieMap;
}
}
输出如下:
上传结果同第一节用客户端上传的一样。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)