S3 boto列出密钥有时返回目录密钥

15

我注意到boto API返回值在不同的存储桶位置上有所不同。我有以下代码:

con = S3Connection(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
bucket = con.get_bucket(S3_BUCKET_NAME)
keys = bucket.list(path)
for key in keys:
  print key

我正在对两个存储桶运行,一个在美国西部,另一个在爱尔兰。这个存储桶中的路径是一个子目录,在爱尔兰,我可以获取到这个子目录以及其下的任何键(文件),但在美国西部,我只能获取到该子目录下的键。

因此,爱尔兰给出:

<Key: <bucketName>,someDir/>
<Key: <bucketName>,someDir/someFile.jpg>
<Key: <bucketName>,someDir/someOtherFile.jpg>

而美国标准则是:

<Key: <bucketName>,someDir/someFile.jpg>
<Key: <bucketName>,someDir/someOtherFile.jpg>

显然,我希望能够编写相同的代码,而不受存储桶位置的影响。有人知道我可以采取什么措施来解决此问题,以便获得相同可预测的结果吗?甚至是否是boto引起了问题或S3引起了问题。我注意到在爱尔兰命名存储桶有不同的策略,不同的地区是否具有自己的api版本?

谢谢,

Steve


1
尚未进行广泛测试,但北加利福尼亚似乎与爱尔兰做了相同的事情。不确定哪个是期望的结果。 - Steven Franklin
好问题,确实是一个非常烦人的差异 - 我很确定除了_US Standard_之外的所有地区都会返回相同的结果(即用于模拟目录的专用对象/键),有关详细信息,请参见我的答案 - Steffen Opel
1
为确保分析实际上挖掘到了正确的源头:这些存储桶/密钥最初是如何创建的?更具体地说,这些是由第三方服务/工具创建的,还是通过_S3 API_或_AWS管理控制台_由您自己创建的? - Steffen Opel
好的观点,我有一些用控制台上传的密钥,也有一些是通过boto创建的。我想我会研究一下它们是否对两者都表现出相同的行为方式。 - Steven Franklin
我有相同的经历,但是使用的是boto3,并且在同一个AWS账户的不同存储桶上下文中。当通过objects.filter()按前缀列出一个存储桶的内容时,它也返回文件夹,但对于其他存储桶,它只返回文件。 - Oleksandr
5个回答

22

感谢Steffen的建议,他建议看一下如何创建密钥。通过进一步调查,我认为我对这里发生的事情有了把握。我最初的假设是它与存储桶区域有关,但那只是一个误导。似乎是由于管理控制台在操作密钥时所做的事情造成的。

如果您在管理控制台中创建目录,则会创建一个0字节密钥。当执行列表操作时,将返回此密钥。

如果您使用boto创建/上传文件,则不会创建文件夹。有趣的是,如果您在文件夹中删除文件(从AWS控制台中),则会为曾经包含该密钥的文件夹创建一个密钥。如果然后再次使用boto上传文件,则在UI上看起来完全相同的结构实际上您具有一个多余的目录密钥。这就是我的问题所在,因为我正在测试我们的应用程序,所以我正在清除键,然后发现不同的结果。

值得知道这种情况。UI中没有任何指示来显示文件夹是否是已创建的(将返回为密钥)还是解释性的(基于密钥名称)。


1
非常感谢您进行分析并跟进,+1!幕后的魔术确实让人有些困惑…… - Steffen Opel
AWS控制台正在创建一个名为“bucketName/someDir/”的空文件,这相当令人困惑;您可以从命令行中删除该空“文件”,然后问题就解决了。 - Switch

6

我无法给你一个明确的答案,但至少可以提供一些部分答案:

背景

目录/文件夹模拟

Amazon S3实际上没有本地文件夹/目录的概念,而是由存储桶和对象/键组成的扁平存储体系 - 在大多数S3工具(包括AWS Management Console)中看到的目录样式呈现仅基于约定,即用相同前缀模拟对象的层次结构 - 有关此架构的更多详细信息,请参见我在如何指定不匹配目录的对象过期前缀?中的答案,包括来自AWS文档的引用/参考。

区域API差异

我注意到爱尔兰命名存储桶的策略不同, 不同地区是否有自己的api版本?

这显然是Amazon S3的情况,它是他们最早推出的服务之一,例如请参见Bucket Restrictions and Limitations

在除美国标准区域之外的所有区域,必须使用以下指南来命名存储桶。[...] [我强调]

这些针对美国标准区域的具体规定也在S3文档的其他地方看到,并且美国标准本身与否则明显受地理限制的区域相比是一个不寻常的构造:

US Standard — 使用位于美国的Amazon S3服务器

这是默认区域。美国标准区域会使用网络地图将请求自动路由到北弗吉尼亚或太平洋西北地区的设施。要使用此区域,请在控制台中创建存储桶时选择“US Standard”作为区域。美国标准区域提供所有请求的最终一致性。 [我强调]

这种隐式CDN行为是S3的这个默认区域(即美国标准)独有的,我认为在任何其他AWS服务中都没有看到。

可能的原因

我有一点模糊的记忆,即S3实际上在更近期的区域(即除了US Standard)的模拟目录/文件夹中将零字节对象/键放入桶中,而对于US Standard区域的旧解决方案可能不同,例如仅基于已建立的命名约定进行目录分隔,通过/并完全省略专用对象/键。

解决方案

如果分析正确,恐怕除了维护两种情况下的不同代码路径外,你无法做任何事情。

祝好运!


5

我曾经遇到过同样的问题。作为一个解决方法,您可以过滤掉所有具有结尾为 '/' 的键,以消除“目录”条目。

def files(keys):
    return (key for key in keys if not key.name.endswith('/'))

s3 = boto.connect_s3(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
bucket = s3.get_bucket(S3_BUCKET_NAME)
keys = bucket.list(path)
for key in files(keys):
    print(key)

1

你可以使用size参数来排除前缀:

for key in keys: 
  if key.size > 0:
  print key

0

我利用“文件夹”在其路径中没有“.”的事实。 而文件则有。 media/images 不会被删除 media/images/sample.jpg 将被删除

例如,清理存储桶文件

def delete_all_bucket_files(self,bucket_name):
        bucket = self.get_bucket(bucket_name)
        if bucket:
            for key in bucket.list():
                #delete only the files, not the folders
                if period_char in key.name:
                    print 'deleting: ' + key.name
                    key.delete()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接