Вопрос по amazon-s3, ruby, folder – Список каталогов на заданном уровне в Amazon S3

4

Я храню два миллиона файлов в корзине Amazon 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. Я не хочу перечислять все ключи, это займет намного больше времени.

Я открыт для непосредственного использования API-интерфейса AWS, однако я до сих пор играл с гемом right_aws в rubyhttp://rdoc.info/projects/rightscale/right_aws

В этом геме есть как минимум два API, я попытался использовать bucket.keys () в модуле S3 и incrementally_list_bucket () в модуле S3Interface. Например, я могу установить префикс и разделитель для перечисления всех l1 / a1 / *, но не могу понять, как перечислить только первый уровень в l1. В хэше есть запись: common_prefixes, возвращаемая incrementally_list_bucket (), но в моем тестовом примере она не заполнена.

Возможна ли эта операция с S3 API?

Спасибо!

Орен, ты прав, это работает сейчас. Большое спасибо. Возможно, созданная мной структура тестовой корзины была неправильной. Marius Seritan
Проверьте документацию S3 для операции ListBucket:docs.amazonwebservices.com/AmazonS3/2006-03-01/..., Для получения a1-a5000 укажите префикс = "/ L1 /» = разделитель "/", Для получения / l1 / a123 / * укажите префикс = "/ L1 / a123 /», delimeter = "/", Это то, что вы имели в виду? Oren Trutner

Ваш Ответ

2   ответа
0

Эта ветка довольно старая, но я недавно столкнулся с этой проблемой и хотел заявить о своих 2cents ...

Похоже, что хлопотным является полторы списки папок по пути в корзине S3. Большинство современных оболочек для гемов вокруг S3 API (официальный сервис AWS-SDK, S3) не• правильно анализировать возвращаемый объект (в частности 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
6

right_aws позволяет сделать это как часть их основногоS3Interface класс, но вы можете создать свой собственный метод для более простого (и приятного) использования. Поместите это в верхней части вашего кода:

  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 общих префиксов.

Удивительно, что это невстроенный до сих пор, но это сэкономило мне много времени. Благодарю. drudru
Я немного улучшил это здесь:stackoverflow.com/questions/4849939/... (в нем также перечислены отдельные файлы сейчас). Еще можно'не верю, что это неОн встроен в один из множества драгоценных камней Ruby S3. Erik

Похожие вопросы