列出 Cloud Storage 中的文件 (Android)

借助 Cloud Storage for Firebase,您可以列出 Cloud Storage 存储桶的内容。SDK 会返回当前 Cloud Storage 引用下的对象的项和前缀。

使用 List API 的项目需要使用 Cloud Storage for Firebase 规则版本 2。如果您已有一个 Firebase 项目,请按照安全规则指南中的步骤操作。

list() 使用 Google Cloud Storage List API。在 Cloud Storage for Firebase 中,我们使用 / 作为分隔符来模拟文件系统语义。为了高效遍历大型分层 Cloud Storage 存储桶,List API 会将前缀和项分开返回。例如,如果您上传一个文件 /images/uid/file1,则:

  • root.child('images').listAll() 将返回 /images/uid 作为前缀。
  • root.child('images/uid').listAll() 将返回该文件作为项。

Cloud Storage for Firebase SDK 不会返回包含两个连续的 / 或以 / 结尾的对象路径。例如,假设一个存储桶中包含以下对象:

  • correctPrefix/happyItem
  • wrongPrefix//sadItem
  • lonelyItem/

对此存储桶中的项执行列出操作返回的结果如下:

  • 在根目录中执行列出操作将返回对 correctPrefixwrongPrefixlonelyItem 的引用作为 prefixes
  • correctPrefix/ 中执行列出操作将返回对 correctPrefix/happyItem 的引用作为 items
  • wrongPrefix/ 中执行列出操作不会返回任何引用,因为 wrongPrefix//sadItem 包含两个连续的 /
  • lonelyItem/ 中执行列出操作不会返回任何引用,因为对象 lonelyItem// 结尾。

列出所有文件

您可以使用 listAll 提取某个目录的所有结果。此方法最适合用于小型目录,因为所有结果都会保留在内存缓冲区中。如果在操作期间系统添加或移除了对象,该操作也可能不会返回一致的快照。

大型列表更适合使用分页的 list() 方法,因为 listAll() 会在内存缓冲区中保留所有结果。

以下示例演示了 listAll

Kotlin+KTX

val storage = Firebase.storage
val listRef = storage.reference.child("files/uid")

// You'll need to import com.google.firebase.storage.component1 and
// com.google.firebase.storage.component2
listRef.listAll()
    .addOnSuccessListener { (items, prefixes) ->
        for (prefix in prefixes) {
            // All the prefixes under listRef.
            // You may call listAll() recursively on them.
        }

        for (item in items) {
            // All the items under listRef.
        }
    }
    .addOnFailureListener {
        // Uh-oh, an error occurred!
    }

Java

StorageReference listRef = storage.getReference().child("files/uid");

listRef.listAll()
        .addOnSuccessListener(new OnSuccessListener<ListResult>() {
            @Override
            public void onSuccess(ListResult listResult) {
                for (StorageReference prefix : listResult.getPrefixes()) {
                    // All the prefixes under listRef.
                    // You may call listAll() recursively on them.
                }

                for (StorageReference item : listResult.getItems()) {
                    // All the items under listRef.
                }
            }
        })
        .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                // Uh-oh, an error occurred!
            }
        });

将列出的结果分页

list() API 对返回的结果数设置了限制。list() 会提供一致的分页视图,并提供一个让您可以控制何时提取更多结果的 pageToken。

该 pageToken 会对上一条结果中返回的最后一项的路径和版本进行编码。在后续请求中使用该 pageToken,系统会返回位于该 pageToken 后面的项。

以下示例演示了如何将结果分页:

Kotlin+KTX

fun listAllPaginated(pageToken: String?) {
    val storage = Firebase.storage
    val listRef = storage.reference.child("files/uid")

    // Fetch the next page of results, using the pageToken if we have one.
    val listPageTask = if (pageToken != null) {
        listRef.list(100, pageToken)
    } else {
        listRef.list(100)
    }

    // You'll need to import com.google.firebase.storage.component1 and
    // com.google.firebase.storage.component2
    listPageTask
        .addOnSuccessListener { (items, prefixes, pageToken) ->
            // Process page of results
            processResults(items, prefixes)

            // Recurse onto next page
            pageToken?.let {
                listAllPaginated(it)
            }
        }.addOnFailureListener {
            // Uh-oh, an error occurred.
        }
}

Java

public void listAllPaginated(@Nullable String pageToken) {
    FirebaseStorage storage = FirebaseStorage.getInstance();
    StorageReference listRef = storage.getReference().child("files/uid");

    // Fetch the next page of results, using the pageToken if we have one.
    Task<ListResult> listPageTask = pageToken != null
            ? listRef.list(100, pageToken)
            : listRef.list(100);

    listPageTask
            .addOnSuccessListener(new OnSuccessListener<ListResult>() {
                @Override
                public void onSuccess(ListResult listResult) {
                    List<StorageReference> prefixes = listResult.getPrefixes();
                    List<StorageReference> items = listResult.getItems();

                    // Process page of results
                    // ...

                    // Recurse onto next page
                    if (listResult.getPageToken() != null) {
                        listAllPaginated(listResult.getPageToken());
                    }
                }
            }).addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    // Uh-oh, an error occurred.
                }
            });
}

处理错误

如果您尚未将安全规则升级到版本 2,则 list()listAll() 会失败。如果您看到以下错误,请升级您的安全规则:

Listing objects in a bucket is disallowed for rules_version = "1".
Please update storage security rules to rules_version = "2" to use list.

系统也可能会显示其他错误消息,指出用户没有适当的权限。如需详细了解这些错误,请参阅处理错误