我将200万个文件存储在亚马逊S3存储桶中。下面有一个给定的根(l1),l1下的目录列表,然后每个目录包含文件。所以我的桶看起来像下面的
l1/a1/file1-1.jpg
l1/a1/file1-2.jpg
l1/a1/... another 500 files
l1/a2/file2-1.jpg
l1/a2/file2-2.jpg
l1/a2/... another 500 files
....
l1/a5000/file5000-1.jpg
我想尽快列出第二级条目,所以我想得到a1,a2,a5000。我不想列出所有的密钥,这将花费更长的时间。
我愿意直接使用AWS api,但是到目前为止,我已经使用ruby中的right_aws gem进行了游戏http://rdoc.info/projects/rightscale/right_aws
该gem中至少有两个API,我尝试在S3模块中使用bucket.keys(),在S3Interface模块中使用incrementally_list_bucket()。例如,我可以设置前缀和分隔符列出所有l1 / a1 / *,但我无法弄清楚如何仅列出l1中的第一级。在incrementally_list_bucket()返回的哈希中有一个:common_prefixes条目,但是在我的测试样本中它没有被填充。
使用S3 API可以进行此操作吗?
谢谢!
答案 0 :(得分:6)
right_aws
允许将此作为其基础S3Interface
类的一部分,但您可以创建自己的方法,以便更轻松(更好)地使用。把它放在代码的顶部:
module RightAws
class S3
class Bucket
def common_prefixes(prefix, delimiter = '/')
common_prefixes = []
@s3.interface.incrementally_list_bucket(@name, { 'prefix' => prefix, 'delimiter' => delimiter }) do |thislist|
common_prefixes += thislist[:common_prefixes]
end
common_prefixes
end
end
end
end
这会将common_prefixes
方法添加到RightAws::S3::Bucket
类。现在,您可以使用mybucket.keys
来获取一系列公共前缀,而不是调用mybucket.common_prefixes
来获取存储桶中的密钥列表。在你的情况下:
mybucket.common_prefixes("l1/")
# => ["l1/a1", "l1/a2", ... "l1/a5000"]
我必须说我只用少量公共前缀测试它;你应该检查这是否适用于超过1000个公共前缀。
答案 1 :(得分:0)
这个帖子已经很老了但是我最近遇到过这个问题,想要断言我的2cents ......
在S3存储桶中给出路径的干净地列出文件夹是一个麻烦的一半(似乎)。 S3 API(AWS-SDK官方,S3)周围的大多数当前gem包装器都没有正确解析返回对象(特别是CommonPrefixes),因此很难找回文件夹列表(分隔符噩梦)。
对于那些使用S3宝石的人来说,这是一个快速修复...对不起它不是一个尺寸,但它是我想做的最好。
https://github.com/qoobaa/s3/issues/61
代码段:
module S3
class Bucket
# this method recurses if the response coming back
# from S3 includes a truncation flag (IsTruncated == 'true')
# then parses the combined response(s) XML body
# for CommonPrefixes/Prefix AKA directories
def directory_list(options = {}, responses = [])
options = {:delimiter => "/"}.merge(options)
response = bucket_request(:get, :params => options)
if is_truncated?(response.body)
directory_list(options.merge({:marker => next_marker(response.body)}), responses << response.body)
else
parse_xml_array(responses + [response.body], options)
end
end
private
def parse_xml_array(xml_array, options = {}, clean_path = true)
names = []
xml_array.each do |xml|
rexml_document(xml).elements.each("ListBucketResult/CommonPrefixes/Prefix") do |e|
if clean_path
names << e.text.gsub((options[:prefix] || ''), '').gsub((options[:delimiter] || ''), '')
else
names << e.text
end
end
end
names
end
def next_marker(xml)
marker = nil
rexml_document(xml).elements.each("ListBucketResult/NextMarker") {|e| marker ||= e.text }
if marker.nil?
raise StandardError
else
marker
end
end
def is_truncated?(xml)
is_truncated = nil
rexml_document(xml).elements.each("ListBucketResult/IsTruncated") {|e| is_truncated ||= e.text }
is_truncated == 'true'
end
end
end