Список объектов в папке на Amazon S3 без ТАКЖЕ Список объектов в подпапки


Я с помощью Amazon S3 и на Java SDK для получения списка файлов в (имитация) подпапку. Этот код является довольно стандартным (AWSConfiguration - это класс, который содержит кучу счету определенного значения):

String prefix = "/images/cars/";
int prefix_size = prefix.length();
AmazonS3 s3 = new AmazonS3Client(new AWSConfiguration());
ObjectListing objectListing = s3.listObjects(new ListObjectsRequest().
    withBucketName(AWSConfiguration.BUCKET).
    withPrefix(prefix));

Теперь в этот список будут включены такие объекты, как /картинки/авто/по умолчанию.ПНГ , а также /изображения/автомобили/Форд/по умолчанию.ПНГ (потому что оба они содержат один и тот же префикс). В списке только те объекты, которые находятся непосредственно внутри /фото/автомобили/ "папку" у меня есть следующая функция (в классе называемый S3Asset)

public static boolean isInsideFolder(int root_size, String key) {
  return (key.substring(root_size).indexOf("/") == -1);
}

Это похоже на полный ключ для любого / после префикса как понять, что он находится внутри вложенных папок. Это позволяет мне перебирать объекты с помощью следующего кода (я обрезки префикс для ясности):

for(S3ObjectSummary objectSummary : objectListing.getObjectSummaries()) {
  if(S3Asset.isInsideFolder(prefix_size, objectSummary.getKey())) {
    System.out.println(objectSummary.getKey().substring(prefix_size));
  }
}

Насколько я могу сказать, что это самый чистый способ сделать это, но она имеет одну особенность, которая мне не нравится. Если я смотрю в папку корневом уровне я прошу имена всех файлов во всех подпапках только перебрать их и узнаем, что есть только один объект в папки корневом уровне. Я считал связь ключа с значение на полный путь к папке, которая позволила бы мне запросить объекты с предсказуемым ключ вместо префикса, но основным недостатком является то, что ключ должен быть сгенерирован код, и поэтому активы загружены непосредственно в к S3 ведро (через консоль управления) бы не этот ключ. Кто-нибудь есть идея получше?



68114
17
задан 14 декабря 2011 в 07:12 Источник Поделиться
Комментарии
1 ответ

В ListObjectsRequest документации есть метод под названием withDelimiter(разделитель строк). Добавление .withDelimiter("/") после .withPrefix(префикс) вызов, то вы получите только список объектов, в той же папке уровня, в качестве префикса (избегая необходимости фильтровать ObjectListing после того, как список был послан по проводу).

Некоторые замечания по поводу кода:

1, я бы извлечь из локальной переменной для ListObjectsRequest экземпляр:

final ListObjectsRequest listObjectRequest = new ListObjectsRequest().
withBucketName(AWSConfiguration.BUCKET).
withPrefix(prefix);
final ObjectListing objectListing = s3.listObjects(listObjectRequest);

Это легче читать.

2, root_size должны быть rootSize. (В отношении конвенций Java-кодирования.)

3, я бы использовал строку.содержит вместо помощи indexOf. Это более осмысленно, легче читать, поскольку вы не должны использовать -1 магическое число.

4, в последнем фрагменте я хотел создать локальную переменную для ключа:

for (final S3ObjectSummary objectSummary: objectListing.getObjectSummaries()) {
final String key = objectSummary.getKey();
if (S3Asset.isImmediateDescendant(prefix, key)) {
final String relativePath = getRelativePath(prefix, key);
System.out.println(relativePath);
}
}

5, Кроме того, я бы переместить продолжительность звонков внутри вспомогательный метод:

public String getRelativePath(final String parent, final String child) {
if (!child.startsWith(parent)) {
throw new IllegalArgumentException("Invalid child '" + child
+ "' for parent '" + parent + "'");
}
// a String.replace() also would be fine here
final int parentLen = parent.length();
return child.substring(parentLen);
}

public boolean isImmediateDescendant(final String parent, final String child) {
if (!child.startsWith(parent)) {
// maybe we just should return false
throw new IllegalArgumentException("Invalid child '" + child
+ "' for parent '" + parent + "'");
}
final int parentLen = parent.length();
final String childWithoutParent = child.substring(parentLen);
if (childWithoutParent.contains("/")) {
return false;
}
return true;
}

Обратите внимание на регистрация вход. (Эффективная Java, второе издание, пункт 38: проверка параметров на валидность)

Многочисленные призывы длина может выглядеть излишними и медленно, но преждевременная оптимизация-это не очень хорошая вещь (см. эффективная Java, второе издание, пункт 55: оптимизировать рассудительно). Если вы проверьте источник на Java.яз.Строки, вы найдете это:

/** The count is the number of characters in the String. */
private final int count;

...

public int length() {
return count;
}

Строка является неизменным, поэтому легко кэшировать его длина и JDK делает это для вас.

20
ответ дан 14 декабря 2011 в 09:12 Источник Поделиться