功能丰富的 Perl: Amazon S3 上的储存管理 (用于管理 S3 bucket 及其内容的 3 个 CPAN)

来源:互联网 发布:淘宝双十一的由来 编辑:程序博客网 时间:2024/04/28 22:49
Teodor Zlatanov, 程序员, Gold Software Systems

简介: 了解 Perl 程序员如何使用 3 个 CPAN S3 模块 —— Net::Amazon::S3Amazon::S3SOAP::Amazon::S3 —— 来列出、创建和删除 bucket(S3 数据储存);列出、创建、获取和删除 bucket 中的项;以及获得一个项的元数据。

Perl 开发人员拥有一个出色的资源,即 Comprehensive Perl Archive Network (CPAN)。Amazon 也有一个出色的资源 Simple Storage Service (S3)。尽管在 CPAN 上存在一个官方的 Amazon S3 Perl 库(称为 S3),但是 S3 涉及到至少 5 个或 6 个模块(不过有些不是完全独立的)。这好像一场辣椒烹饪比赛,出场的不是 200 人,而是 2000 人。

现在,我在比赛结束后的一天出现了,和您分享最佳的烹饪秘诀。这些模块和工具在 CPAN 上免费提供,您可以立即使用它们。我推荐 3 个属于这三个模块的秘方:Net::Amazon::S3、Amazon::S3 和 SOAP::Amazon::S3。

从 developerWorks 上的 功能丰富的 Perl:Perl 和 Amazon 云 系列阅读关于 S3 的优点和缺点的讨论。没有必要在这里重复讨论,不过我会简单总结一下。

S3 是由 Amazon 提供和管理的储存服务。Amazon 对用户的访问收费,因此不用担心服务器、备份、带宽可用性和分布等。因此,S3 和日常生活中的许多物品一样,是廉价便利的,并且由您决定它是否适合您的业务或个人需求。

S3 数据和 bucket 中的数据项通过 bucket(与域名大致相似)组织起来。提醒一下,在上传时一定要保护 MIME 类型,否则您将下载到原始的二进制数据(这对映像的影响尤其大)。MIME 类型和其他元数据在写入之后就不能再更改 —— 您必须删除并重新创建该项。

在深入探索之前声明一下,本文针对具有中等水平的 Perl 程序员。本文不详细解释基础的 Perl 技术。此外,您应该知道什么是 S3 以及如何安装 CPAN 模块。如果您还没具备这些条件,请查看 参考资料 部分获取背景介绍资源。

本文的目标

联系 Ted

Ted 是一位非常受欢迎并且很多产的作者。查看 Ted 的个人简介 并和他以及 My developerWorks 上的其他作者、读者交流。

我借助 3 个模块(Net::Amazon::S3、Amazon::S3 和 SOAP::Amazon::S3)解释如何执行一系列基础的 S3 操作,并展示必要的源代码,如下所示:

  • 列出、创建和删除 bucket
  • 列出、创建、获取和删除 bucket 中的项
  • 获取项的元数据

为了让这些任务在模块之间具有可比性,我重用了相同的命令行选项和总体结构。


Net::Amazon::S3

了解 Moose

Moose 的主要目标是让 Perl 5 OOP 更加易于使用、更加一致,从而减轻程序员的压力。通过帮助您 “放开” 面向对象编程的机制,Moose 帮助您关注您想实现的目标。构建在 Class::MOP 之上的 Moose 也使得元类编程更加容易。如果您还没有尝试过这些特性,那么应该尝试一下;它是用 Perl 处理 OOP 的出色方式。在 参考资料 中更多地了解 Moose。

Net::Amazon::S3 模块是一个著名的模块,它受到广泛的支持,功能也很全面。它有一些前提条件,但要比 Moose 合理得多(如果您了解的话)。

我们将把 S3 密匙作为 S3KEYS3SECRET 储存在环境中。 这样,我们就可以通过 Perl 以 $ENV{S3KEY}$ENV{S3SECRET} 的形式访问它们。这种在文件中储存数据的方法是一种比较安全的保护隐私性的方法(记住,如果 S3 密匙被盗,您将为他人购买带宽)。

现在,Net::Amazon::S3 已经安装完毕。(您最好使用推荐的 Net::Amazon::S3::Client 接口,因为 Net::Amazon::S3 被称为 “旧有接口”。但是 Net::Amazon::S3::Client version 0.50 由于 Moose 模块而存在一个 bug,因此我在撰写本文时不能使用它。这个 bug 在 version 0.51 已经修复,当前的版本是 0.52)。现在让我们探索例子。和以往一样,下载 小节提供所有脚本。


清单 1. net-amazon-s3.pl 准备


#!/usr/bin/perl

use warnings;
use strict;
use Data::Dumper;
use Getopt::Long;
use Net::Amazon::S3;
use MIME::Types;

my $mime = MIME::Types->new();

 

这是标准的代码,包括用于调试目的的 Data::Dumper。这里创建了一个泛型的 MIME 对象,尽管我们仅在上传时使用它。


清单 2. net-amazon-s3.pl 选项、帮助函数和初始 S3 连接


my %opts = (
key => $ENV{S3KEY},
secret => $ENV{S3SECRET},
separator => '/',
);

GetOptions(
/%opts,
"create|c=s",
"delete|d=s",
"list|l:s", # the parameter is optional
"keys|k",
"metadata|m",
"get=s",
"put=s",
"separator=s",
"help|h",
);

unless ($opts{key} && $opts{secret} )
{
die "$0 requires the S3KEY and S3SECRET environment variables to be set.";
}

# handle -h
usage() if exists $opts{help};

my $s3 = Net::Amazon::S3->new(
aws_access_key_id => $opts{key},
aws_secret_access_key => $opts{secret},
retry => 1,
);

die "Could not connect to S3" unless defined $s3;


sub read_filename
{
print "/nEnter filename: ";
my $name = <>;
chomp $name;
return $name;
}

sub usage
{
print lt;<EOHIPPUS;

$0 [OPTIONS]

Pass your S3 key and secret in the S3KEY and S3SECRET environment entries.

Options:
--help or -h : this help
--separator $opts{separator} : BUCKET and KEY separator character
(for --get and --put)
--create BUCKET (or -c BUCKET) : create BUCKET
--delete BUCKET (or -d BUCKET) : delete BUCKET
--delete BUCKET$opts{separator}KEY : delete KEY in BUCKET
--list [BUCKET] (or -l) : list a specific bucket or all buckets
--keys (or -k) : list the keys in each bucket (requires --list)
--metadata (or -m) : show the keys' metadata
(requires --keys and --list)
--get BUCKET$opts{separator}KEY : download KEY from BUCKET
--put BUCKET$opts{separator}KEY : upload a file to KEY in BUCKET

EOHIPPUS

exit 0;
}

 

这是更加标准的代码。选项是在这里设置的。usage() 函数非常全面,这让程序更加有用。列出并简单解释了每个选项。


清单 3. net-amazon-s3.pl 创建和删除操作


if (exists $opts{create})
{
my $bucket = $s3->add_bucket( { bucket => $opts{create}} )
or die sprintf ("%s: %s", $s3->err, $s3->errstr);
print "Created bucket '$opts{create}' successfully./n";
}
elsif (exists $opts{delete})
{
my ($b, $key) = split $opts{separator}, $opts{delete};
my $bucket = $s3->bucket($b);
die "Could not retrieve bucket $b" unless $bucket;
if (defined $key)
{
$bucket->delete_key($key)
or die sprintf ("%s: %s", $s3->err, $s3->errstr);
print "Deleted key '$key' in bucket '$b' successfully./n";
}
else
{
$bucket->delete_bucket()
or die sprintf ("%s: %s", $s3->err, $s3->errstr);
print "Deleted bucket '$b' successfully./n";
}
}

 

--create 选项非常简单。您仅需创建 bucket 并返回。

对于 --delete,它处理 bucket 删除(非递归的,因此用户必须先删除 bucket 中的所有密匙)或 bucket 中的密匙删除。在这里,分隔符作为 bucket 名和密匙名的分隔点。


清单 4. net-amazon-s3.pl 的 get 和 put 操作


...
elsif (exists $opts{get})
{
my ($b, $key) = split $opts{separator}, $opts{get};
my $bucket = $s3->bucket($b);
die "Could not get the bucket $b" unless $bucket;
my $where = read_filename();
my $response = $bucket->get_key_filename( $key, 'GET', $where )
or die sprintf ("%s: %s", $s3->err, $s3->errstr);
die "Could not create file $where" unless -f $where;
print "Successfully downloaded $key from bucket $b into $where/n";
}
elsif (exists $opts{put})
{
my ($b, $key) = split $opts{separator}, $opts{put};
my $bucket = $s3->bucket($b);
die "Could not get the bucket $b" unless $bucket;
my $where = read_filename();
die "File $where does not exist or is not readable" unless -f $where && -r $where;

my $response = $bucket->add_key_filename(
$key,
$where,
{ content_type => $mime->mimeTypeOf($where), },
)
or die sprintf ("%s: %s", $s3->err, $s3->errstr);
print "Successfully uploaded $where into $key in bucket $b/n";
}

 

Getput 非常相似,它们都是在文件名和密匙名上操作的。在这里,最有趣的是 MIME::Types $mime 对象,我们使用它来获取内容的类型。记住,在上传之后就不能再更改它。


清单 5. net-amazon-s3.pl 的 list 操作


...
elsif (exists $opts{list})
{
print "Available buckets:/n";

my @todo;

if ($opts{list})
{
push @todo, map { $s3->bucket($_) } $opts{list};
}
else
{
print "(Getting all buckets)/n";
my $response = $s3->buckets;
die "Could not get the bucket list" unless $response;
@todo = @{$response->{buckets}};
}

foreach my $bucket ( @todo )
{
printf "/t%s/n", $bucket->bucket;

if (exists $opts{keys})
{
my $response = $bucket->list_all
or die sprintf ("%s: %s", $s3->err, $s3->errstr);

foreach my $key (@{$response->{keys}})
{
printf "/t/t%10s/t%s/n", $key->{size}, $key->{key};
if (exists $opts{metadata})
{
my $detail = $bucket->get_key($key->{key});
foreach my $entry (qw/content_length content_type etag/)
{
printf "/t/t/t%20s=%s/n", $entry, ($detail->{$entry}||'UNDEFINED');
}
}
}
}
}
}

 

最后并且也是最长的是 --list 事件处理程序,它将处理一个或多个 bucket。它将显示密匙及其元数据的列表。

/t 字符被转换成制表符;它的作用是为输出提供粗略的缩进,让它在文本中具有更好的格式。

如您所见,Net::Amazon::S3 是一个非常干净的模块。其中的一部分方法有点奇怪,但它们能够出色地工作。在获取项和将它们与元数据一起使用之间存在一个断点,这需要用到一个额外的 get_key() 调用。该模块的所有代码都是简短的。


Amazon::S3

Amazon::S3 模块是 Net::Amazon::S3 的替换。我必须更改 new() 调用以使用散列引用,不过这也是唯一需要更改的地方(很明显,还要将所有 Net::Amazon::S3 引用更改为 Amazon::S3)。


清单 6. 从 net-amazon-s3.pl 更改而来的 amazon-s3.pl


my $s3 = Amazon::S3->new({
aws_access_key_id => $opts{key},
aws_secret_access_key => $opts{secret},
retry => 1,
});

 

Amazon::S3 支持许多选项;请参考文档看看是否可以使用它们。一般而言,Amazon::S3 的目标好像与 Net::Amazon::S3 稍有不同,但是从开发人员的角度看,它们的 API 是相同的。这对库的互操作性非常有益。

您可能很欣赏 Amazon::S3 的一个特性,即它不像 Net::Amazon::S3 那样依赖许多模块。他的开发者还强调它是可移植的,这对需要它的人而言是件好事。


SOAP::Amazon::S3

探索 File::Slurp

File::Slurp 模块提供的代替项允许您仅使用一个简单的调用来读或写整个文件。它们的目标是简单易用,以及能够灵活地传入或获取文件内容。除了 ... 之外,还有一个代替项可以读取一个目录下的所有文件。这些代替项适用于文件、管道、套接字、stdio、伪文件和 DATA。要更多地了解 File::Slurp,请查看 参考资料。

学习 SOAP::Amazon::S3 模块需要了解一些背景知识,我将针对本文稍作介绍。SOAP 是通过 HTTP(Web)访问信息的一种方式,它与使用路径表示资源的常见 HTTP 请求不同。这些请求通常被称为是 REST 式的,并且趋向于发展成许多 URL 变体;相反,SOAP 仅命中一小部分 URL,并且将所有 XML 传递给服务器。

我很希望能够继续谈 SOAP,但这是一个非常广泛的主题,因此我把它留给读者去探索。对于其价值,SOAP 和 REST 的差别并不是很大。您使用哪种方法都可以编写出出色或糟糕的代码。

不幸的是,SOAP::Amazon::S3 在文档中被标记为处于试验阶段。您应该亲自测试它,看看是否适合您。

谈论区别。首先,我们需要 File::Slurp 模块,因为 SOAP::Amazon::S3 不能像 Net::Amazon::S3 和 Amazon::S3 那样提供上传和下载文件的便利方法。


清单 7. soap-amazon-s3.pl 准备


# set Debug to 0 if you don't want to see all the XML
my $s3 = SOAP::Amazon::S3->new( $opts{key}, $opts{secret},
{ Debug => 1, RaiseError => 1 } );

 

我忽略了 Debug=1,因为您将怀着好奇心查看 SOAP::Amazon::S3 生成的所有 SOAP 流量。由于 RaiseError=1,所以我对 Net::Amazon::S3 进行的所有错误检查都是不必要的,但这在生产环境中不是好主意。

创建 bucket (my $bucket = $s3->createbucket($opts{create});) 与使用 Net::Amazon::S3 创建 bucket 不同,因为它删除一个 bucket ($bucket->delete()) 或一个对象 ($bucket->object($key)->delete();)。

将数据写到一个文件稍微复杂些,因为如前所述,SOAP::Amazon::S3 不具备 Net::Amazon::S3 中的便利函数。


清单 8. soap-amazon-s3.pl 写文件


open W, '>', $where or die "Could not write to $where: $!";
print W $bucket->object($key)->getdata();
close W;

 

从文件上传也一样要复杂些。


清单 9. soap-amazon-s3.pl 上传文件


my $type = ''.$mime->mimeTypeOf($where); # force $type to be a string

# use File::Slurp::read_file in scalar context to grab the whole file's contents
my $data = read_file($where);
$bucket->putobject($key, $data, { 'Content-Type' => $type });

 

MIME 类型必须装在一个字符串中,否则将影响 XML 帮助函数模块。此外,内容类型的大写化也与 Net::Amazon::S3 不同。

最后,我们讨论列出项。在这里,SOAP::Amazon::S3 不像 Net::Amazon::S3 那样强大,因为对象元数据不可用。SOAP::Amazon::S3 有一个出色的 $object->url() 方法,但它没有将空间转换成 %20,因此您要试用它,看看是否适合您。我提交了一个 bug(记住,这还是一个实验模型),但是现在我避开了生产环境中的 $object->url() 方法。


清单 10. soap-amazon-s3.pl 列出 bucket 和其中的对象


...
elsif (exists $opts{list})
{
print "Available buckets:/n";

my @todo;

if ($opts{list})
{
push @todo, map { $s3->bucket($_) } $opts{list};
}
else
{
print "(Getting all buckets)/n";
@todo = $s3->listbuckets;
}

foreach my $bucket ( @todo )
{
printf "/t%s/n", $bucket->name;

if (exists $opts{keys})
{
foreach my $key ($bucket->list())
{
printf "/t/t%10s/t%-30s/t%s/n", $key->{Size}, $key->name, $key->url;
if (exists $opts{metadata})
{
foreach my $entry (qw/Size ETag LastModified/)
{
printf "/t/t/t%20s=%s/n", $entry, ($key->{$entry}||'UNDEFINED');
}
}
}
}
}
}

 

如您所见,SOAP::Amazon::S3 没有获取元数据,因此您不能看到对象的内容类型等。如果您使用元数据来储存关于对象的重要信息时,这是一个令人不愉快的限制。如果不存在该限制的话,SOAP::Amazon::S3 在列出 bucket 及其元素方面可以与 Net::Amazon::S3 媲美。


结束语

我没有详细评估另外两个 S3 CPAN 模块,而是在这里简要概括一下:

  • 如果您想要通过命令行访问 S3,Net::Amazon::S3::Tools 是不错的选择。这比自己编写好,因此您可以使用现成的工具测试它。
  • 如果仅处理单个 bucket,Tie::Amazon::S3 是不错的模块。您可以删除或修改散列条目和添加新的条目等等。不幸的是,它不允许 bucket 级别的操作(创建 bucket 和删除 bucket 等)或元数据操作(尤其是在新的密匙上设置内容类型)。因此,如果您想要在 S3 中储存纯数据,Tie::Amazon::S3 是非常有用的,但它对映像的用途不大。

总体而言,Net::Amazon::S3 和 Amazon::S3 目前是处理 S3 的最佳选择。它们的互操作性 API 能够在必要时进行切换。它们支持所有操作,上至 bucket 操作,下至元数据获取。它们的 API 有些奇怪,但在设置之后很容易使用。

关注一下 SOAP::Amazon::S3,它很有潜力。如果您在单个 bucket 中处理纯数据,那么最好使用 Tie::Amazon::S3,因为它能够提供很多方便。

祝您使用 S3 愉快!

 


下载

描述名字大小下载方法样例脚本amazon-s3-scripts.zip5KBHTTP

关于下载方法的信息

 

参考资料

学习

  • 更多地了解 Amazon S3。
  • 功能丰富的 Perl:Perl 和 Amazon 云 系列(developerWorks,2009 年 3 - 6 月)逐步介绍了如何使用 Perl 和 Apache 构建一个简单的照片分享 Web 站点,用于访问 Amazon 的 Simple Storage Service (S3) 和 SimpleDB:
    • 功能丰富的 Perl:Perl 和 Amazon 云,第 1 部分 通过阐述 S3 和 SimpleDB 的结构介绍它们的优点和缺点。
    • 功能丰富的 Perl:Perl 和 Amazon 云,第 2 部分 显示如何通过 HTML 表单从 Web 页面将文件上传到 S3,从而最大限度地减轻服务器的压力,并维护严格的安全性策略。
    • 功能丰富的 Perl:Perl 和 Amazon 云,第 3 部分 详细介绍 URL 如何为已上传的文件创建 SimpleDB 记录,以及如何以 SimpleDB 记录的形式在照片上创建、编辑和删除评论。
    • 功能丰富的 Perl:Perl 和 Amazon 云,第 4 部分 检查了完整的 mod_perl 站点的代码库,包括如何配置顶级,如何处理事件处理程序,以及如何设置外部依赖项。
    • 功能丰富的 Perl:Perl 和 Amazon 云,第 5 部分 检查完整的 mod_perl 站点的模板,包括一个用于索引的模板,三个用于上传的模板,一个用于图像和内容浏览的模板,以及一个以递归的方式浏览图像评论的模板。
  • 您对 Moose 感兴趣吗?请查看它和 File::Slurp。
  • 要了解更多关于 SOAP 和 REST 的信息,请查看 developerWorks SOA 和 Web 服务 专区。
  • 在 developerWorks Linux 专区 寻找为 Linux 开发人员(包括 Linux 新手入门)准备的更多参考资料,查阅我们 最受欢迎的文章和教程。
  • 在 developerWorks 上查阅所有 Linux 技巧 和 Linux 教程。
  • 随时关注 developerWorks 技术活动和网络广播。

获得产品和技术

  • 在 CPAN (Comprehensive Perl Archive Network) 站点上,您可以找到大量模块和模块文档。这里提供 Net-Amazon-S3-0.current modules;Amazon-S3-0.current modules 和 SOAP-Amazon-S3-0.current modules。此外,还包含两个我没有讲到的模块:Net-Amazon-S3-Tools-0.current 和 Tie-Amazon-S3-0.current。
  • 使用可直接从 developerWorks 下载的 IBM 产品评估试用版软件 构建您的下一个 Linux 开发项目。

讨论

  • 加入 My developerWorks 社区。查看开发人员参与的博客、论坛、组和 wiki,并与其他 developerWorks 用户交流。

原创粉丝点击