65.9K
CodeProject 正在变化。 阅读更多。
Home

从C#开发人员的角度看Amazon S3

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (17投票s)

2010年6月2日

CPOL

6分钟阅读

viewsIcon

85464

downloadIcon

2341

本文展示了如何直接从 C# 与 Amazon S3 存储进行交互。

引言

本文从 C# 开发人员的角度描述了 Amazon S3。它展示了如何从 C# 访问 Amazon S3 服务、可以使用哪些操作以及如何对它们进行编程。

文章中的示例使用了 Amazon SDK for .NET。使用 SDK 需要一个 Amazon EC2 账户,还需要访问密钥和私有密钥才能开始使用。更多详细信息请参阅此链接

Amazon S3 被称为简单存储服务,但它不仅简单,而且非常强大。它支持许多在日常工作中可以使用的功能。当然,主要功能是通过键来存储数据。

存储服务

您可以按键在 S3 中存储任何数据,然后访问和读取它。但是,要做到这一点,首先需要创建一个存储桶。存储桶在 C# 语言中类似于命名空间。AWS 账户限制为 100 个存储桶,并且所有存储桶名称在所有 Amazon 账户中共享。因此,您必须为其选择一个唯一的名称。更多详细信息请参阅此链接

让我们看看如何检查存储桶是否已创建,以及如何在不存在时创建它

ListBucketsResponse response = client.ListBuckets();

bool found = false;
foreach (S3Bucket bucket in response.Buckets)
{
    if (bucket.BucketName == BUCKET_NAME)
    {
        found = true;
        break;
    }
}

if (found == false)
{
    client.PutBucket(new PutBucketRequest().WithBucketName(BUCKET_NAME));
}

其中“client”是 Amazon.S3.AmazonS3Client 对象。您可以在本文附带的示例中看到如何初始化它。

让我们运行代码并检查存储桶是否已真正创建。我使用 EC2Studio (Microsoft Visual Studio 的插件) 通过 UI 操作 S3。

这里显示了将某些数据存储到某个存储桶中的某个键的代码

PutObjectRequest request = new PutObjectRequest();
request.WithBucketName(BUCKET_NAME);
request.WithKey(S3_KEY);
request.WithContentBody("This is body of S3 object.");
client.PutObject(request);

在这里,S3 对象是使用常量 S3_KEY 中定义的键创建的,并将一个字符串写入其中。

文件的内容也可以放入 S3(而不是字符串)。要做到这一点,代码需要稍作修改

PutObjectRequest request = new PutObjectRequest();
request.WithBucketName(BUCKET_NAME);
request.WithKey(S3_KEY);
request.WithFilePath(pathToFile);
client.PutObject(request);

要写入文件,应该使用 WithFilePath 方法而不是 WithContentBody 方法。有关 S3 对象,请参阅此链接

现在,让我们确保数据确实已写入 S3

在 EC2Studio 插件的 S3 浏览器中看到 S3 对象后,双击它并选择一个程序来显示其内容。屏幕截图显示 S3Object 已创建,并且其内容在记事本中打开。

从 C# 代码读取 S3 对象

GetObjectRequest request = new GetObjectRequest();
request.WithBucketName(BUCKET_NAME);
request.WithKey(S3_KEY);
GetObjectResponse response = client.GetObject(request);
StreamReader reader = new StreamReader(response.ResponseStream);
String content = reader.ReadToEnd();

元数据

除了 S3 对象内容之外,还可以将元数据(键/值对)与对象关联。以下是如何执行此操作的示例

CopyObjectRequest request = new CopyObjectRequest();
request.DestinationBucket = BUCKET_NAME;
request.DestinationKey = S3_KEY;
request.Directive = S3MetadataDirective.REPLACE;
NameValueCollection metadata = new NameValueCollection();
// Each user defined metadata must start from "x-amz-meta-"
metadata.Add("x-amz-meta-test", "Test data");
request.AddHeaders(metadata);
request.SourceBucket = BUCKET_NAME;
request.SourceKey = S3_KEY;
client.CopyObject(request);

Amazon S3 没有特殊的 API 调用来将元数据与 S3 对象关联。取而代之的是,应该调用 Copy 方法。

但是 S3 API 有一个特殊的读取元数据的方法

GetObjectMetadataRequest request = new GetObjectMetadataRequest();
request.WithBucketName(BUCKET_NAME).WithKey(S3_KEY);
GetObjectMetadataResponse response = client.GetObjectMetadata(request);
foreach (string key in response.Metadata.AllKeys)
{
    Console.Out.WriteLine("   key: " + key + ", value: " + response.Metadata[key]);
}

让我们通过 EC2Studio 插件看看元数据是否已分配

s3_ec2studio/screen3.png

HTTP 访问

好消息是,S3 不仅可以通过 API 调用访问 S3 对象,还可以直接通过 HTTP 访问(因此每个 S3 对象都有一个 URL,可用于任何 Web 浏览器访问它)。您可以将 S3 用作简单的静态 HTTP 服务器,在那里托管您的静态 Web 内容。

此外,S3 具有访问控制功能,允许限制可以访问数据的用户(有关 ACL 访问的更多信息,请参阅下文)。不仅是谁,还有何时……

Amazon SDK API 允许生成一个仅在有限时间内有效的签名 URL。以下是生成有效期为一周的 URL 的代码

GetPreSignedUrlRequest request = 
    new GetPreSignedUrlRequest().WithBucketName(BUCKET_NAME).WithKey(S3_KEY);
request.WithExpires(DateTime.Now.Add(new TimeSpan(7, 0, 0, 0)));
string url = client.GetPreSignedURL(request));

并且可以通过 EC2Studio 插件完成相同的操作

s3_ec2studio/screen4.png

然后,您可以将 URL 发送给任何人,并确信他们对数据的访问将在指定时间后停止。

日志记录

谈到在 Amazon S3 上托管静态 Web 内容时,应该提及日志访问功能,因为您应该知道谁何时访问您的网站。

S3 具有此功能。首先,您应该为存储桶配置日志记录。这可以通过 API 完成,但这是一个相当罕见的操作,所以让我们仅使用 EC2Studio 插件为存储桶打开日志记录。

s3_ec2studio/screen5.png

必须定义存储您的日志文件的目标存储桶。可以定义一个前缀来了解这些日志文件来自哪里。

结果,对存储桶中的任何对象的每次访问都将被记录到目标存储桶,并且 Amazon S3 将不时创建包含日志信息的日志文件。可以使用读取任何 S3 对象的常规 API 调用来读取该文件。

但它有一个特殊的格式,不太方便查看,所以让我们再次使用 EC2Studio 来查看日志信息。

更多详细信息请参阅此链接

访问控制列表

如前所述,Amazon S3 具有定义访问的功能。有两种访问类型:按用户 ID/电子邮件,或按 URL(这意味着预定义组或用户)

s3_ec2studio/screen7.png

因此,您可以定义读写访问权限,并定义谁可以读取和写入任何 S3 对象或存储桶的 ACL。

有一个特殊的 API 调用来设置或读取 ACL;例如,可以找到 S3Object 的所有者,如

GetACLResponse response = client.GetACL
    (new GetACLRequest().WithBucketName(BUCKET_NAME).WithKey(S3_KEY));
Console.Out.WriteLine("Object owner is " + response.AccessControlList.Owner.DisplayName);

更多详细信息请参阅此链接

版本

Amazon S3 的另一个很酷的功能是版本控制。您可以为存储桶启用版本控制,当您将任何对象放入其中时,它不会被简单地替换,而是会创建新版本并存储在相同的键下。这样您就可以访问和管理对象的所有版本(修改)。

可以通过以下调用检索 S3 对象的所有版本

ListVersionsResponse response = client.ListVersions
    (new ListVersionsRequest().WithBucketName(BUCKET_NAME).WithPrefix(S3_KEY));
Console.Out.WriteLine("Found the following versions for prefix " + S3_KEY);
foreach (S3ObjectVersion version in response.Versions)
{
    Console.Out.WriteLine("   version id: " + version.VersionId + ", 
    last modified time: " + version.LastModified);
}

通过 UI 访问版本

s3_ec2studio/screen8.png

要删除特定对象版本,可以使用 client.DeleteObject。所需的版本 ID 应作为请求参数。

访问对象也是如此。可以通过 client.GetObject 并将版本 ID 作为请求参数来读取版本。

更多详细信息请参阅此链接

像文件系统一样

如果您使用任何 S3 浏览器(EC2Studio 插件或其他),您会注意到它们都将 S3 存储表示为文件系统,而它只是一个键/值存储。此外,大多数工具主要将 S3 显示为文件存储(通常用于备份文件)。如前所述,它具有许多普通文件系统中不存在的酷功能。因此,S3 可以用作更通用的存储来保存应用程序数据。

拥有分层结构很有用,S3 也支持它。S3Object 的每个键都可以具有特殊的定界符(通常使用“/”,但您可以定义自己的定界符),它们将完整的键分割成一些路径。您可以为定义的路径(目录)请求 S3 对象列表

ListObjectsRequest req = new ListObjectsRequest();
req.WithBucketName(BUCKET_NAME);
req.WithPrefix(DIR_NAME);
ListObjectsResponse res = client.ListObjects(req);
Console.Out.WriteLine("Enumerating all objects in directory: " + DIR_NAME);
foreach (S3Object obj in res.S3Objects)
{
    Console.Out.WriteLine("   S3 object key: " + obj.Key);
}

并且可以在 UI 中查看相同的内容

s3_ec2studio/screen9.png

结论

Amazon S3 服务是一项功能齐全的服务,可以从 C# 代码中用于存储应用程序数据,为数据定义附加元数据,并能够定义谁何时可以访问您的数据。查看数据访问日志。而且,还有版本存储功能,可以定义分层结构。

历史

  • 2010 年 6 月 2 日:首次发布。
© . All rights reserved.