【问题标题】:Efficient way to extract files and meta data from Amazon S3?从 Amazon S3 提取文件和元数据的有效方法?
【发布时间】:2012-06-12 02:30:46
【问题描述】:

是否有更有效的方法来列出 Amazon S3 中存储桶中的文件并提取每个文件的元数据?我正在使用 AWS PHP 开发工具包。

if ($paths = $s3->get_object_list('my-bucket')) {
    foreach($paths AS $path) {
        $meta = $s3->get_object_metadata('my-bucket', $path);
        echo $path . ' was modified on ' . $meta['LastModified'] . '<br />';
    }
}

目前我需要运行get_object_list() 来列出所有文件,然后运行get_object_metadata() 来获取每个文件的元数据。

如果我的存储桶中有 100 个文件,它会进行 101 次调用来获取这些数据。如果可以在 1 个电话中完成,那就太好了。

例如:

if ($paths = $s3->get_object_list('my-bucket')) {
    foreach($paths AS $path) {
        echo $path['FileName'] . ' was modified on ' . $path['LastModified'] . '<br />';
    }
}

【问题讨论】:

  • 使用 s3 对象来存储“文件”就像使用整个 2Gb fs 分区来存储您的 Zork 图像。将所有元数据放在一个对象中。是的,100 个对象需要 100 个事务。

标签: amazon-s3


【解决方案1】:

我知道这有点老了,但我遇到了这个问题,为了解决这个问题,我扩展了 Aws sdk 以使用批处理功能来解决这类问题。它可以更快地检索大量文件的自定义元数据。 这是我的代码:

    /**
     * Name: Steves_Amazon_S3
     * 
     * Extends the AmazonS3 class in order to create a function to 
     * more efficiently retrieve a list of
     * files and their custom metadata using the CFBatchRequest function.
     * 
     * 
     */
    class Steves_Amazon_S3 extends AmazonS3 {

        public function get_object_metadata_batch($bucket, $filenames, $opt = null) {
            $batch = new CFBatchRequest();

            foreach ($filenames as $filename) {

                $this->batch($batch)->get_object_headers($bucket, $filename); // Get content-type
            }

            $response = $this->batch($batch)->send();

            // Fail if any requests were unsuccessful
            if (!$response->areOK()) {
                return false;
            }
            foreach ($response as $file) {
                $temp = array();
                $temp['name'] = (string) basename($file->header['_info']['url']);
                $temp['etag'] = (string) basename($file->header['etag']);
                $temp['size'] = $this->util->size_readable((integer) basename($file->header['content-length']));
                $temp['size_raw'] = basename($file->header['content-length']);
                $temp['last_modified'] = (string) date("jS M Y H:i:s", strtotime($file->header['last-modified']));
                $temp['last_modified_raw'] = strtotime($file->header['last-modified']);
                @$temp['creator_id'] = (string) $file->header['x-amz-meta-creator'];
                @$temp['client_view'] = (string) $file->header['x-amz-meta-client-view'];
                @$temp['user_view'] = (string) $file->header['x-amz-meta-user-view'];

                $result[] = $temp;
            }

            return $result;
        }
    }

【讨论】:

    【解决方案2】:

    你需要知道list_objects 函数是有限制的。它不允许加载超过 1000 个对象,即使 max-keys 选项将设置为某个较大的数字。

    要解决此问题,您需要多次加载数据:

    private function _getBucketObjects($prefix = '', $booOneLevelOny = false)
    {
        $objects = array();
        $lastKey = null;
        do {
            $args = array();
            if (isset($lastKey)) {
                $args['marker'] = $lastKey;
            }
    
            if (strlen($prefix)) {
                $args['prefix'] = $prefix;
            }
    
            if($booOneLevelOny) {
                $args['delimiter'] = '/';
            }
    
            $res = $this->_client->list_objects($this->_bucket, $args);
            if (!$res->isOK()) {
                return null;
            }
    
            foreach ($res->body->Contents as $object) {
                $objects[] = $object;
                $lastKey = (string)$object->Key;
            }
            $isTruncated = (string)$res->body->IsTruncated;
            unset($res);
        } while ($isTruncated == 'true');
    
        return $objects;
    }
    

    结果 - 您将获得对象的完整列表。


    如果您有一些自定义标题怎么办? 它们不会通过list_objects 函数返回。在这种情况下,这将有所帮助:

    foreach (array_chunk($arrObjects, 1000) as $object_set) {
        $batch = new CFBatchRequest();
        foreach ($object_set as $object) {
            if(!$this->isFolder((string)$object->Key)) {
                $this->_client->batch($batch)->get_object_headers($this->_bucket, $this->preparePath((string)$object->Key));
            }
        }
    
        $response = $this->_client->batch($batch)->send();
    
        if ($response->areOK()) {
            foreach ($response as $arrHeaderInfo) {
                $arrHeaders[] = $arrHeaderInfo->header;
            }
        }
        unset($batch, $response);
    }
    

    【讨论】:

    • 这正是我所需要的。非常感谢!
    • @CoreDumpError 不客气 :) 我喜欢这个网站,因为问题很有趣,答案可能非常不同且有用!
    【解决方案3】:

    我最终使用了list_objects 函数,该函数提取了我需要的 LastModified 元数据。

    一次通话:)

    【讨论】:

      猜你喜欢
      • 2021-11-18
      • 2012-06-23
      • 2015-02-09
      • 2018-12-24
      • 2017-03-24
      • 2015-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多