Android에서 Cloud Storage로 파일 나열

Firebase용 Cloud Storage를 사용하면 Cloud Storage 버킷의 콘텐츠를 나열할 수 있습니다. SDK는 현재 Cloud Storage 참조 아래에 있는 객체의 항목과 프리픽스를 반환합니다.

프로젝트에서 List API를 사용하는 경우 Firebase용 Cloud Storage 규칙 버전 2가 필요합니다. 기존 Firebase 프로젝트가 있는 경우 보안 규칙 가이드에 설명된 단계를 따르세요.

list()Google Cloud Storage List API를 사용합니다. Firebase용 Cloud Storage에서는 파일 시스템 시맨틱스를 에뮬레이션할 수 있는 구분 기호로 /를 사용합니다. Cloud Storage 버킷의 규모가 큰 계층적 데이터를 효율적으로 순회하기 위해 List API는 프리픽스와 항목을 별도로 반환합니다. 예를 들어 파일 하나(/images/uid/file1)를 업로드하는 경우 다음과 같습니다.

  • root.child('images').listAll()은 프리픽스로 /images/uid를 반환합니다.
  • root.child('images/uid').listAll()은 항목으로 파일을 반환합니다.

Firebase용 Cloud Storage SDK는 / 두 개가 연속되어 있거나 /로 끝나는 객체 경로를 반환하지 않습니다. 버킷에 다음과 같은 객체가 있는 경우를 예로 들어 보겠습니다.

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

이 버킷의 항목에 대한 list 작업의 결과는 다음과 같습니다.

  • 루트에서 list 작업을 실행할 경우 correctPrefix, wrongPrefix, lonelyItem에 대한 참조가 prefixes로 반환됩니다.
  • correctPrefix/에서 list 작업을 실행할 경우 correctPrefix/happyItem에 대한 참조가 items로 반환됩니다.
  • wrongPrefix/에서 list 작업을 실행할 경우 wrongPrefix//sadItem/ 두 개가 연속되어 있으므로 참조가 반환되지 않습니다.
  • lonelyItem/에서 list 작업을 실행할 경우 lonelyItem/ 객체가 /로 끝나기 때문에 참조가 반환되지 않습니다.

모든 파일 나열

listAll을 사용하여 디렉터리의 모든 결과를 가져올 수 있습니다. 모든 결과가 메모리에 버퍼링되므로 이 작업은 작은 디렉터리에 사용하는 것이 가장 좋습니다. 처리하는 중 객체가 추가되거나 삭제되면 일관된 스냅샷이 반환되지 않을 수도 있습니다.

listAll()은 메모리에 모든 결과를 버퍼링하므로 목록의 크기가 큰 경우에는 페이지로 나뉘는 list() 메서드를 사용합니다.

다음은 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 작업 결과를 페이지로 나누기

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.

사용자에게 올바른 권한이 없음을 나타내는 다른 오류가 발생할 수도 있습니다. 오류의 자세한 내용은 오류 처리를 참조하세요.