S3总结

AWS S3对象存储

Amazon Simple Storage Service (Amazon S3) 是一种面向 Internet 的存储服务。您可以通过Amazon S3随时在Web上的任何位置存储和检索的任意大小的数 据。Amazon S3 特意内置了着重于简易性和稳健性的最小功能集。以下是 Amazon S3 服务的一些优势:

创建存储桶 – 创建和命名存储数据的存储桶。存储桶是 Amazon S3 中用于数据存储的基础容器。
在存储桶中存储数据 – 在存储桶中存储无限量的数据。可将所需数量的对象上传到 Amazon S3 存储桶。每个对象可包含最多 5TB的数据。使用开发人员分配的唯一键值存储和检索每个对象。

下载数据 – 下载您的数据或允许其他人下载。随时下载您的数据或允许其他人执行相同的操作。
权限 - 对于要在您的 Amazon S3 存储桶中上传或下载数据的其他人员,您可授予其访问权限或拒绝其访问。将上传和下载的许可授予3种类型的用户。身份验证机制可帮助确保数据安全,以防未授权访问
标准接口 – 使用标准的REST接口(SOAP接口已弃用),它们可与任何 Internet 开发工具包搭配使用

1.1.1 存储桶(bucket)

我们的数据都是存储在AWS 的存储桶中,我们可以把桶理解为磁盘分区,不过它是由一个桶名(字符串)唯一标识,即你不能创建别人已经创建过的桶。以下是S3 存储桶命名规则:
在S3中的所有现有存储桶名称中必须唯一
必须符合DNS命名约定
名称长度必须为至少3个字符,且不能超过 63 个字符
名称不能包含大写字符或下划线
名称必须以小写字母或数字开头
名称必须是一系列的一个或多个标签。相邻标签通过单个句点 (.) 分隔。名称可以包含小写字母、数字和连字符。每个标签都必须以小写字母或数字开头和结尾
名称不得采用IP地址格式
当通过安全套接字 (SSL) 使用虚拟托管式存储桶时,SSL通配符证书仅匹配不包含句点的存储桶。要解决此问题,请使用 HTTP或编写自己的证书验证逻辑

1.1.2 对象

对象是 Amazon S3 中存储的基本实体。对象由对象数据和元数据组成。数据部分对S3不透明。元数据是一组描述对象的名称-值对。其中包括一些默认元数据 (如上次修改日期) 和标准 HTTP 元数据 (如 Content-Type)。您还可在存储对象时指定自定义元数据。
在存储桶中,对象将由键 (名称) 和版本 ID 进行唯一标识
S3数据模型是一种扁平结构。不存在子存储桶或子文件夹层次结构;但可用键名称前缀和分隔符推断逻辑层次结构
键名称中的以下字符可能需要进行代码处理,且可能需要以16进制形式在URL中编码或引用。其中部分字符是不可打印的字符,浏览器可能无法处理,这也需特殊处理

选择 说明 其他
表示和的符号 (“&”) 美元 (“$”) ASCII 字符范围 00–1F 十六进制 (0–31 十进制) 和 7F (127 十进制)
“At”符号 (“@”) 等于 (“=”) 分号 (“;”)
冒号 (“:”) 加号 (“+”) 空格 – 大量连续空格可能会在某些使用情形中丢失 (特别是多个空格)
逗号 (“,”) 问号 (“?”)
1.1.3 对象标签(tag)

使用存储对象打标签对存储进行分类。每个标签都是一个键-值对。
您可以将标签添加到新对象 (当您上传新对象时),也可以将标签添加到现有对象。请注意以下几点:

您最多可以将 10 个标签与对象关联。与对象关联的标签必须具有唯一的标签键。
标签键的长度最大可以为 128 个 Unicode 字符,标签值的长度最大可以为 256 个 Unicode 字符。
键和值区分大小写。
标签对于对象管理相当好用所以重点说明
利用标签,您现在获得了另一个维度。如果您希望 photo1 属于项目 x 类别,则可以相应地标记该对象。除了数据分类之外,标签还提供其他好处。例如:

对象标签支持权限的精细访问控制。例如,您可以向一个 IAM 用户授予仅读取带有特定标签的对象的权限。
对象标签支持精细的对象生命周期管理,在其中,除了在生命周期规则中指定键名称前缀之外,还可以指定基于标签的筛选条件。
使用 Amazon S3 分析时,您可以配置筛选条件,以便按对象标签、键名称前缀或前缀和标签的组合对对象进行分组以进行分析。
您还可以自定义 Amazon CloudWatch 指标以按特定标签筛选条件显示信息。以下各节提供了详细信息。

S3存储类型

Amazon S3 中的每个对象都有与之关联的存储类别

avatar

对于经常访问的存储类均为STANDARD,我们默认也是该存储类
创建对象时,要指定键名称(Key),它在存储桶中唯一地标识该对象。可以理解为存储文件相对于当前桶的路径。

S3数据一致性模型

S3在所有区域为S3存储桶中的新对象的PUTS提供写后读一致性,但要注意,如果在创建对象前对键名发出HEAD或GET请求 (查看该对象是否存在)S3提供写后读最终一致性。

S3在所有区域提供最终一致性用于覆盖PUTS和DELETES。

单个键的更新是原子更新。例如,如果您对一个现有键执行PUT操作,则后续读取可能会返回旧数据或已更新的数据,但它永远不会返回损坏的数据或部分数据。

S3通过在卓越亚马逊数据中心内的多个服务器间复制数据,从而实现高可用。如果PUT请求成功,则数据已安全存储。但有关更改的信息必须在S3间进行复制,这可能需要一些时间,因此您可能会观察到以下行为:

这是一个过程,会将一个新对象写入S3,并立即列出其存储桶内的键。在充分传播此更改前,此对象可能不会显示在列表
这是一个过程,会替换一个现有对象,并立即尝试读取此对象。在充分传播此更改前,S3可能会返回先前的数据
这是一个过程,会删除一个现有的对象,并立即尝试读取此对象。在充分传播此删除前,S3可能会返回删除的数据
这是一个过程,会删除一个现有的对象,并立即列出其存储桶内的键。在充分传播此删除前,S3可能会列出删除的对象
注意: S3目前不支持对象锁定。如果同时对同一键发出2个PUT请求,则以带有最新时间戳的请求为准。如果这会导致问题,您需在应用程序中创建对象锁定机制。

更新基于键值; 无法跨键值实现原子更新。例如,无法根据一个键值的更新对另一键值进行更新,除非将此功能设计到应用程序

代码实例操作

Java创建存储桶

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import java.io.IOException;

import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.CreateBucketRequest;
import com.amazonaws.services.s3.model.GetBucketLocationRequest;

public class CreateBucket {

public static void main(String[] args) throws IOException {
String clientRegion = "*** Client region ***";
String bucketName = "*** Bucket name ***";

try {
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
.withCredentials(new ProfileCredentialsProvider())
.withRegion(clientRegion)
.build();

if (!s3Client.doesBucketExistV2(bucketName)) {
// Because the CreateBucketRequest object doesn't specify a region, the
// bucket is created in the region specified in the client.
s3Client.createBucket(new CreateBucketRequest(bucketName));

// Verify that the bucket was created by retrieving it and checking its location.
String bucketLocation = s3Client.getBucketLocation(new GetBucketLocationRequest(bucketName));
System.out.println("Bucket location: " + bucketLocation);
}
}
catch(AmazonServiceException e) {
// The call was transmitted successfully, but Amazon S3 couldn't process
// it and returned an error response.
e.printStackTrace();
}
catch(SdkClientException e) {
// Amazon S3 couldn't be contacted for a response, or the client
// couldn't parse the response from Amazon S3.
e.printStackTrace();
}
}
}

Java删除存储桶

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import java.util.Iterator;

import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.ListVersionsRequest;
import com.amazonaws.services.s3.model.ObjectListing;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import com.amazonaws.services.s3.model.S3VersionSummary;
import com.amazonaws.services.s3.model.VersionListing;

public class DeleteBucket {

public static void main(String[] args) {
String clientRegion = "*** Client region ***";
String bucketName = "*** Bucket name ***";

try {
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
.withCredentials(new ProfileCredentialsProvider())
.withRegion(clientRegion)
.build();

// Delete all objects from the bucket. This is sufficient
// for unversioned buckets. For versioned buckets, when you attempt to delete objects, Amazon S3 inserts
// delete markers for all objects, but doesn't delete the object versions.
// To delete objects from versioned buckets, delete all of the object versions before deleting
// the bucket (see below for an example).
ObjectListing objectListing = s3Client.listObjects(bucketName);
while (true) {
Iterator<S3ObjectSummary> objIter = objectListing.getObjectSummaries().iterator();
while (objIter.hasNext()) {
s3Client.deleteObject(bucketName, objIter.next().getKey());
}

// If the bucket contains many objects, the listObjects() call
// might not return all of the objects in the first listing. Check to
// see whether the listing was truncated. If so, retrieve the next page of objects
// and delete them.
if (objectListing.isTruncated()) {
objectListing = s3Client.listNextBatchOfObjects(objectListing);
} else {
break;
}
}

// Delete all object versions (required for versioned buckets).
VersionListing versionList = s3Client.listVersions(new ListVersionsRequest().withBucketName(bucketName));
while (true) {
Iterator<S3VersionSummary> versionIter = versionList.getVersionSummaries().iterator();
while (versionIter.hasNext()) {
S3VersionSummary vs = versionIter.next();
s3Client.deleteVersion(bucketName, vs.getKey(), vs.getVersionId());
}

if (versionList.isTruncated()) {
versionList = s3Client.listNextBatchOfVersions(versionList);
} else {
break;
}
}

// After all objects and object versions are deleted, delete the bucket.
s3Client.deleteBucket(bucketName);
}
catch(AmazonServiceException e) {
// The call was transmitted successfully, but Amazon S3 couldn't process
// it, so it returned an error response.
e.printStackTrace();
}
catch(SdkClientException e) {
// Amazon S3 couldn't be contacted for a response, or the client couldn't
// parse the response from Amazon S3.
e.printStackTrace();
}
}
}

可配置存储桶的生命周期以使对象过期,S3随后将删除过期对象。可添加生命周期配置规则,以使所有或部分带特定键名称前缀的对象过期。e.g.,要删除存储桶中所有对象,可将生命周期规则设置为使对象在创建一天后过期。在S3删除所有对象后,可删除或保留存储桶.(未启用版本控制的存储桶,可直接删除所有对象,然后删除存储桶。启用了版本控制的存储桶,必须先删除所有对象版本,然后再删除存储桶)
Java管理存储桶的网站配置(要将网站配置添加到存储桶,请提供存储桶名称和网站配置。网站配置必须包含索引文档,且可包含可选的错误文档。这些文档必须已存在于存储桶)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import java.io.IOException;

import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.BucketWebsiteConfiguration;

public class WebsiteConfiguration {

public static void main(String[] args) throws IOException {
String clientRegion = "*** Client region ***";
String bucketName = "*** Bucket name ***";
String indexDocName = "*** Index document name ***";
String errorDocName = "*** Error document name ***";

try {
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
.withRegion(clientRegion)
.withCredentials(new ProfileCredentialsProvider())
.build();

// Print the existing website configuration, if it exists.
printWebsiteConfig(s3Client, bucketName);

// Set the new website configuration.
s3Client.setBucketWebsiteConfiguration(bucketName, new BucketWebsiteConfiguration(indexDocName, errorDocName));

// Verify that the configuration was set properly by printing it.
printWebsiteConfig(s3Client, bucketName);

// Delete the website configuration.
s3Client.deleteBucketWebsiteConfiguration(bucketName);

// Verify that the website configuration was deleted by printing it.
printWebsiteConfig(s3Client, bucketName);
}
catch(AmazonServiceException e) {
// The call was transmitted successfully, but Amazon S3 couldn't process
// it, so it returned an error response.
e.printStackTrace();
}
catch(SdkClientException e) {
// Amazon S3 couldn't be contacted for a response, or the client
// couldn't parse the response from Amazon S3.
e.printStackTrace();
}
}

private static void printWebsiteConfig(AmazonS3 s3Client, String bucketName) {
System.out.println("Website configuration: ");
BucketWebsiteConfiguration bucketWebsiteConfig = s3Client.getBucketWebsiteConfiguration(bucketName);
if (bucketWebsiteConfig == null) {
System.out.println("No website config.");
} else {
System.out.println("Index doc: " + bucketWebsiteConfig.getIndexDocumentSuffix());
System.out.println("Error doc: " + bucketWebsiteConfig.getErrorDocument());
}
}
}

上传对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//存储桶的名字
private String bucket_name="beijing";
//自定义上传到bucket后的目录结构
private String key_name="beijing/haidingqu/xierqi/yuanzougaofei.mp3";
//本地文件路径
private String file_path="E:/music/china/yuanzougaofei.mp3";

/**
* 上传文件到指定的bucket中。
* 注意点:这里的本地路径的文件必须存在才行,不然文件不存在回异常。
*/
public void uploadObj(){
final AmazonS3 s3 = new AmazonS3Client();
try {
s3.putObject(bucket_name, key_name, file_path);
} catch (AmazonServiceException e) {
System.err.println(e.getErrorMessage());
System.exit(1);
}
}

列出所有bucket中的对象

1
2
3
4
5
6
7
8
9
10
public void showListObjFromBucket(String bucketName){
final AmazonS3 s3 = new AmazonS3Client();
ObjectListing ol = s3.listObjects(bucketName);

List<S3ObjectSummary> objects = ol.getObjectSummaries();

for (S3ObjectSummary os: objects) {
System.out.println("* " + os.getKey());
}
}

下载对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public void downloadObjByKey(String buketName,String key){
final AmazonS3 s3 = new AmazonS3Client();
try {
S3Object o = s3.getObject(buketName, key);
S3ObjectInputStream s3is = o.getObjectContent();
//下载到指定路径file_path下
FileOutputStream fos = new FileOutputStream(new File(file_path));
byte[] read_buf = new byte[1024];
int read_len = 0;
while ((read_len = s3is.read(read_buf)) > 0) {
fos.write(read_buf, 0, read_len);
}
s3is.close();
fos.close();
} catch (AmazonServiceException e) {
System.err.println(e.getErrorMessage());
System.exit(1);
} catch (FileNotFoundException e) {
System.err.println(e.getMessage());
System.exit(1);
} catch (IOException e) {
System.err.println(e.getMessage());
System.exit(1);
}
}

删除对象

1
2
3
4
5
6
7
8
9
public void deleteObject(String bucket_name, String object_key) {
final AmazonS3 s3 = new AmazonS3Client();
try {
s3.deleteObject(bucket_name, object_key);
} catch (AmazonServiceException e) {
System.err.println(e.getErrorMessage());
System.exit(1);
}
}

参考文章

https://blog.csdn.net/m0_37263637/article/details/80697920
https://blog.csdn.net/u013747798/article/details/85261830
https://blog.csdn.net/zhanglf02/article/details/78500015
https://blog.csdn.net/weixin_33851429/article/details/91907444