如何获取Firebase应用中云存储中所有文件的列表?

时间:2016-05-19 22:30:30

标签: firebase firebase-storage

我正在努力上传图片,一切都很棒,但我有100张图片,我想在我的View中展示所有图片,因为我得到了完整的图片列表文件夹,我找不到这项工作的任何API。

19 个答案:

答案 0 :(得分:86)

由于Firebase SDK for JavaScript release 6.1它有一个列出文件的方法。到目前为止,documentation有点稀疏,因此我建议您查看Rosário's answer了解详细信息。

上一个回答:

Firebase SDK中目前没有API调用,可以在应用内列出云端存储文件夹中的所有文件。如果需要此类功能,则应将文件的元数据(例如下载URL)存储在可以列出的位置。 Firebase Realtime DatabaseCloud Firestore非常适用于此,并且您还可以轻松地与他人共享网址。

您可以在我们的FriendlyPix示例应用中找到一个好的(但有些参与)样本。网络版的相关代码为here,但也有适用于iOS和Android的版本。

或者,您可以使用其中一个服务器端SDK for Cloud Storage列出文件。其中一些内容包含在Firebase Admin SDK中,因此可以轻松开始使用它们。这里要记住的唯一事情是Admin SDK可以完全访问您的所有Firebase服务,因此只能在受信任的环境中使用,例如您的开发机器,您控制的服务器或云功能。

答案 1 :(得分:28)

自2017年3月起:通过添加Firebase Cloud Functions,以及Firebase与Google Cloud的深度集成,现在可以实现。

借助云功能,您可以使用Google Cloud Node程序包在云存储上执行史诗操作。以下示例将所有文件URL从云存储中转换为阵列。每次将某些内容保存到谷歌云存储时,都会触发此功能。

注1 :这是一个计算成本相当高的操作,因为它必须遍历存储桶/文件夹中的所有文件。

注意2 :我这样做只是作为一个例子,没有在承诺等方面付出太多细节。只是为了提出一个想法。

const functions = require('firebase-functions');
const gcs = require('@google-cloud/storage')();

// let's trigger this function with a file upload to google cloud storage

exports.fileUploaded = functions.storage.object().onChange(event => {

  const object = event.data; // the object that was just uploaded
  const bucket = gcs.bucket(object.bucket);
  const signedUrlConfig = { action: 'read', expires: '03-17-2025' }; // this is a signed url configuration object

  var fileURLs = []; // array to hold all file urls 

  // this is just for the sake of this example. Ideally you should get the path from the object that is uploaded :)
  const folderPath = "a/path/you/want/its/folder/size/calculated";

  bucket.getFiles({ prefix: folderPath }, function(err, files) {
    // files = array of file objects
    // not the contents of these files, we're not downloading the files. 

    files.forEach(function(file) {
      file.getSignedUrl(signedUrlConfig, function(err, fileURL) {
        console.log(fileURL);
        fileURLs.push(fileURL);
      });
    });

  });

});

我希望这会给你一般的想法。有关更好的云功能示例,请查看Google's Github repo full of Cloud Functions samples for Firebase。另请查看他们的Google Cloud Node API Documentation

答案 2 :(得分:18)

由于没有列出语言,我将在Swift中回答这个问题。我们强烈建议您同时使用Firebase存储和Firebase实时数据库来完成下载列表:

共享:

// Firebase services
var database: FIRDatabase!
var storage: FIRStorage!
...
// Initialize Database, Auth, Storage
database = FIRDatabase.database()
storage = FIRStorage.storage()
...
// Initialize an array for your pictures
var picArray: [UIImage]()

上载:

let fileData = NSData() // get data...
let storageRef = storage.reference().child("myFiles/myFile")
storageRef.putData(fileData).observeStatus(.Success) { (snapshot) in
  // When the image has successfully uploaded, we get it's download URL
  let downloadURL = snapshot.metadata?.downloadURL()?.absoluteString
  // Write the download URL to the Realtime Database
  let dbRef = database.reference().child("myFiles/myFile")
  dbRef.setValue(downloadURL)
}

下载:

let dbRef = database.reference().child("myFiles")
dbRef.observeEventType(.ChildAdded, withBlock: { (snapshot) in
  // Get download URL from snapshot
  let downloadURL = snapshot.value() as! String
  // Create a storage reference from the URL
  let storageRef = storage.referenceFromURL(downloadURL)
  // Download the data, assuming a max size of 1MB (you can change this as necessary)
  storageRef.dataWithMaxSize(1 * 1024 * 1024) { (data, error) -> Void in
    // Create a UIImage, add it to the array
    let pic = UIImage(data: data)
    picArray.append(pic)
  })
})

有关详细信息,请参阅Zero to App: Develop with Firebase,以及associated source code,了解如何执行此操作的实际示例。

答案 3 :(得分:4)

我在处理项目时也遇到过这个问题。我真的希望他们提供一个结束api方法。无论如何,我就是这样做的: 在将图像上传到Firebase存储时,请创建一个Object并同时将此对象传递给Firebase数据库。该对象包含图像的下载URI。

trailsRef.putFile(file).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
        @Override
        public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
            Uri downloadUri = taskSnapshot.getDownloadUrl();
            DatabaseReference myRef = database.getReference().child("trails").child(trail.getUnique_id()).push();
            Image img = new Image(trail.getUnique_id(), downloadUri.toString());
            myRef.setValue(img);
        }
    });

稍后,当您要从文件夹下载图像时,只需遍历该文件夹下的文件即可。此文件夹与&#34;文件夹&#34;同名在Firebase存储中,但您可以根据需要为其命名。我把它们放在一个单独的线程中。

 @Override
protected List<Image> doInBackground(Trail... params) {

    String trialId = params[0].getUnique_id();
    mDatabase = FirebaseDatabase.getInstance().getReference();
    mDatabase.child("trails").child(trialId).addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            images = new ArrayList<>();
            Iterator<DataSnapshot> iter = dataSnapshot.getChildren().iterator();
            while (iter.hasNext()) {
                Image img = iter.next().getValue(Image.class);
                images.add(img);
            }
            isFinished = true;
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });

现在我有一个包含每个图像的URI的对象列表,我可以做任何我想做的事情。为了将它们加载到imageView中,我创建了另一个线程。

    @Override
protected List<Bitmap> doInBackground(List<Image>... params) {

    List<Bitmap> bitmaps = new ArrayList<>();

    for (int i = 0; i < params[0].size(); i++) {
        try {
            URL url = new URL(params[0].get(i).getImgUrl());
            Bitmap bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
            bitmaps.add(bmp);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    return bitmaps;
}

这将返回一个Bitmap列表,完成后我只需将它们附加到主活动中的ImageView即可。下面的方法是@Override,因为我创建了接口并在其他线程中监听完成。

    @Override
public void processFinishForBitmap(List<Bitmap> bitmaps) {
    List<ImageView> imageViews = new ArrayList<>();
    View v;
    for (int i = 0; i < bitmaps.size(); i++) {
        v = mInflater.inflate(R.layout.gallery_item, mGallery, false);
        imageViews.add((ImageView) v.findViewById(R.id.id_index_gallery_item_image));
        imageViews.get(i).setImageBitmap(bitmaps.get(i));
        mGallery.addView(v);
    }
}

请注意,我必须先等待List Image返回,然后调用thread来处理List Bitmap。在这种情况下,Image包含URI。

    @Override
public void processFinish(List<Image> results) {
    Log.e(TAG, "get back " + results.size());

    LoadImageFromUrlTask loadImageFromUrlTask =  new LoadImageFromUrlTask();
    loadImageFromUrlTask.delegate = this;
    loadImageFromUrlTask.execute(results);
}

希望有人发现它有用。它也将成为我未来的行会。

答案 4 :(得分:4)

使用云功能将图像添加到数据库以跟踪每个上传的图像并将其存储在数据库中的另一种方法。

exports.fileUploaded = functions.storage.object().onChange(event => {

    const object = event.data; // the object that was just uploaded
    const contentType = event.data.contentType; // This is the image Mimme type\

    // Exit if this is triggered on a file that is not an image.
    if (!contentType.startsWith('image/')) {
        console.log('This is not an image.');
        return null;
    }

    // Get the Signed URLs for the thumbnail and original image.
    const config = {
        action: 'read',
        expires: '03-01-2500'
    };

    const bucket = gcs.bucket(event.data.bucket);
    const filePath = event.data.name;
    const file = bucket.file(filePath);

    file.getSignedUrl(config, function(err, fileURL) {
        console.log(fileURL);
        admin.database().ref('images').push({
            src: fileURL
        });
    });
});

此处的完整代码: https://gist.github.com/bossly/fb03686f2cb1699c2717a0359880cf84

答案 5 :(得分:3)

解决方法可以是创建一个内部没有任何内容的文件(即list.txt),在此文件中,您可以使用所有文件列表设置自定义元数据(即Map&lt; String,String&gt;) ; s。如果您需要下载fodler中的所有文件,首先下载list.txt文件的元数据,然后迭代自定义数据并下载地图中包含URL的所有文件

答案 6 :(得分:3)

您可以通过listAll()方法列出Firebase存储目录中的文件。 要使用此方法,必须实现此版本的Firebase存储。 'com.google.firebase:firebase-storage:18.1.1'

https://firebase.google.com/docs/storage/android/list-files

请记住将安全规则升级到版本2。

答案 7 :(得分:2)

对于节点js,我使用了这段代码

const Storage = require('@google-cloud/storage');
const storage = new Storage({projectId: 'PROJECT_ID', keyFilename: 'D:\\keyFileName.json'});
const bucket = storage.bucket('project.appspot.com'); //gs://project.appspot.com
bucket.getFiles().then(results => {
    const files = results[0];
    console.log('Total files:', files.length);
    files.forEach(file => {
      file.download({destination: `D:\\${file}`}).catch(error => console.log('Error: ', error))
    });
}).catch(err => {
    console.error('ERROR:', err);
  });

答案 8 :(得分:1)

从2019年5月开始,Cloud Storage SDK的version 6.1.0支持列出存储桶中的所有对象。您只需要在listAll()中调用Reference

// Since you mentioned your images are in a folder,
// we'll create a Reference to that folder:
var storageRef = firebase.storage().ref("your_folder");


// Now we get the references of these images
storageRef.listAll().then(function(result) {
  result.items.forEach(function(imageRef) {
    // And finally display them
    displayImage(imageRef);
  });
}).catch(function(error) {
  // Handle any errors
});

function displayImage(imageRef) {
  imageRef.getDownloadURL().then(function(url) {
    // TODO: Display the image on the UI
  }).catch(function(error) {
    // Handle any errors
  });
}

注意,要使用此功能,您必须选择加入version 2 of Security Rules,这可以通过将rules_version = '2';设置为安全规则的第一行来完成:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

答案 9 :(得分:1)

用JS

做到这一点

您可以将它们直接附加到div容器,也可以将它们推送到数组。下面显示了如何将它们附加到div。

1)将图像存储在存储中时,使用以下结构在firebase数据库中创建对图像的引用

/images/(imageName){
   description: "" , 
   imageSrc : (imageSource) 
}

2)当您加载文档时,从数据库而不是使用以下代码的存储中提取所有图像源URL

$(document).ready(function(){

var query = firebase.database().ref('images/').orderByKey();
query.once("value").then(function(snapshot){

    snapshot.forEach(function(childSnapshot){

        var imageName = childSnapshot.key;
        var childData = childSnapshot.val();
        var imageSource = childData.url;

        $('#imageGallery').append("<div><img src='"+imageSource+"'/></div>");

    })
})
});

答案 10 :(得分:0)

所以我有一个项目需要从firebase存储下载资产,所以我必须自己解决这个问题。这是如何:

1-首先,制作一个模型数据,例如class Choice{},在该类中定义一个名为image Name的String变量,因此它就像那样

class Choice {
    .....
    String imageName;
}
从数据库/ firebase数据库中取出,将图像名称硬编码到对象,因此如果您有名为Apple.png的图像名称,则创建对象

Choice myChoice = new Choice(...,....,"Apple.png");

3-现在,获取firebase存储中资产的链接

gs://your-project-name.appspot.com/

like this one

4-最后,初始化你的firebase存储引用并开始像这样循环获取文件

storageRef = storage.getReferenceFromUrl(firebaseRefURL).child(imagePath);

File localFile = File.createTempFile("images", "png");
storageRef.getFile(localFile).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {

@Override
public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
    //Dismiss Progress Dialog\\
}

5-就是这样

答案 11 :(得分:0)

您可以使用以下代码。在这里,我将图像上传到firebase存储,然后我将图像下载URL存储到firebase数据库。

//getting the storage reference
            StorageReference sRef = storageReference.child(Constants.STORAGE_PATH_UPLOADS + System.currentTimeMillis() + "." + getFileExtension(filePath));

            //adding the file to reference 
            sRef.putFile(filePath)
                    .addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
                        @Override
                        public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                            //dismissing the progress dialog
                            progressDialog.dismiss();

                            //displaying success toast 
                            Toast.makeText(getApplicationContext(), "File Uploaded ", Toast.LENGTH_LONG).show();

                            //creating the upload object to store uploaded image details 
                            Upload upload = new Upload(editTextName.getText().toString().trim(), taskSnapshot.getDownloadUrl().toString());

                            //adding an upload to firebase database 
                            String uploadId = mDatabase.push().getKey();
                            mDatabase.child(uploadId).setValue(upload);
                        }
                    })
                    .addOnFailureListener(new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception exception) {
                            progressDialog.dismiss();
                            Toast.makeText(getApplicationContext(), exception.getMessage(), Toast.LENGTH_LONG).show();
                        }
                    })
                    .addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
                        @Override
                        public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
                            //displaying the upload progress 
                            double progress = (100.0 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
                            progressDialog.setMessage("Uploaded " + ((int) progress) + "%...");
                        }
                    });

现在要获取存储在firebase数据库中的所有图像,您可以使用

//adding an event listener to fetch values
        mDatabase.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot snapshot) {
                //dismissing the progress dialog 
                progressDialog.dismiss();

                //iterating through all the values in database
                for (DataSnapshot postSnapshot : snapshot.getChildren()) {
                    Upload upload = postSnapshot.getValue(Upload.class);
                    uploads.add(upload);
                }
                //creating adapter
                adapter = new MyAdapter(getApplicationContext(), uploads);

                //adding adapter to recyclerview
                recyclerView.setAdapter(adapter);
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                progressDialog.dismiss();
            }
        });

有关详细信息,您可以看到我的帖子 Firebase Storage Example

答案 12 :(得分:0)

实际上这是可行的,但只能使用Google Cloud API而不是Firebase的一个。这是因为Firebase存储是Google Cloud Storage Bucket,可通过Google Cloud API轻松访问,但是您需要使用OAuth进行身份验证,而不是使用Firebase。

答案 13 :(得分:0)

#In Python

import firebase_admin
from firebase_admin import credentials
from firebase_admin import storage
import datetime
import urllib.request


def image_download(url, name_img) :
    urllib.request.urlretrieve(url, name_img)

cred = credentials.Certificate("credentials.json")

# Initialize the app with a service account, granting admin privileges
app = firebase_admin.initialize_app(cred, {
    'storageBucket': 'YOURSTORAGEBUCKETNAME.appspot.com',
})
url_img = "gs://YOURSTORAGEBUCKETNAME.appspot.com/"
bucket_1 = storage.bucket(app=app)
image_urls = []

for blob in bucket_1.list_blobs():
    name = str(blob.name)
    #print(name)
    blob_img = bucket_1.blob(name)
    X_url = blob_img.generate_signed_url(datetime.timedelta(seconds = 300), method='GET')
    #print(X_url)
    image_urls.append(X_url)


PATH = ['Where you want to save the image']
for path in PATH:
    i = 1
    for url  in image_urls:
        name_img = str(path + "image"+str(i)+".jpg")
        image_download(url, name_img)
        i+=1

答案 14 :(得分:0)

我遇到了同样的问题,我的问题更加复杂。

管理员将音频和pdf文件上传到存储设备:

  • audios / season1,season2 ... / class1,class 2 / .mp3文件

  • books / .pdf文件

Android应用需要获取子文件夹和文件的列表。

解决方案是在存储上捕获上载事件,并使用云功能在firestore上创建相同的结构。

步骤1:在Firestore上手动创建“存储”集合和“音频/书籍”文档

enter image description here

第2步:设置云功能

可能大约需要15分钟:https://www.youtube.com/watch?v=DYfP-UIKxH0&list=PLl-K7zZEsYLkPZHe41m4jfAxUi0JjLgSM&index=1

第3步:使用云功能捕获上传事件

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp(functions.config().firebase);
const path = require('path');

export const onFileUpload = functions.storage.object().onFinalize(async (object) => {
        let filePath = object.name; // File path in the bucket.
        const contentType = object.contentType; // File content type.
        const metageneration = object.metageneration; // Number of times metadata has been generated. New objects have a value of 1.
        if (metageneration !== "1") return;

        // Get the file name.
        const fileName = path.basename(filePath);
        filePath = filePath.substring(0, filePath.length - 1);
        console.log('contentType ' + contentType);
        console.log('fileName ' + fileName);
        console.log('filePath ' + filePath);
        console.log('path.dirname(filePath) ' + path.dirname(filePath));
        filePath = path.dirname(filePath);
        const pathArray = filePath.split("/");
        let ref = '';
        for (const item of pathArray) {
            if (ref.length === 0) {
                ref = item;
            }
            else {
                ref = ref.concat('/sub/').concat(item);
            }
        }

        ref = 'storage/'.concat(ref).concat('/sub')
        admin.firestore().collection(ref).doc(fileName).create({})
                .then(result => {console.log('onFileUpload:updated')})
                .catch(error => {
                    console.log(error);
                });
    });

步骤4:使用Firestore检索Android应用上的文件夹/文件列表

private static final String STORAGE_DOC = "storage/";
    public static void getMediaCollection(String path, OnCompleteListener onCompleteListener) {
        String[] pathArray = path.split("/");
        String doc = null;
        for (String item : pathArray) {
            if (TextUtils.isEmpty(doc)) doc = STORAGE_DOC.concat(item);
            else doc = doc.concat("/sub/").concat(item);
        }
        doc = doc.concat("/sub");

        getFirestore().collection(doc).get().addOnCompleteListener(onCompleteListener);
    }

第5步:获取下载网址

public static void downloadMediaFile(String path, OnCompleteListener<Uri> onCompleteListener) {
        getStorage().getReference().child(path).getDownloadUrl().addOnCompleteListener(onCompleteListener);
    }

注意

由于Firestore不支持检索集合列表,因此我们必须在每个项目上放置“子”集合。

我花了3天的时间找到解决方案,希望最多最多需要3个小时。

干杯。

答案 15 :(得分:0)

扩展RosárioPereira Fernandes'答案:

  1. 在计算机上安装Firebase
npm install -g firebase-tools

  1. 在firebase初始化上,将JavaScript设置为默认语言
  2. 在创建的项目的根文件夹上执行npm installs
   npm install --save firebase
   npm install @google-cloud/storage
   npm install @google-cloud/firestore
   ... <any other dependency needed>
  1. 在项目上添加非默认依赖项,例如
    "firebase": "^6.3.3",
    "@google-cloud/storage": "^3.0.3"

functions / package.json

{
  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "scripts": {
    "lint": "eslint .",
    "serve": "firebase serve --only functions",
    "shell": "firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "engines": {
    "node": "10"
  },
  "dependencies": {
    "@google-cloud/storage": "^3.0.3",
    "firebase": "^6.3.3",
    "firebase-admin": "^8.0.0",
    "firebase-functions": "^3.1.0"
  },
  "devDependencies": {
    "eslint": "^5.12.0",
    "eslint-plugin-promise": "^4.0.1",
    "firebase-functions-test": "^0.1.6"
  },
  "private": true
}

  1. 创建某种listAll函数

index.js

const firebase = require('firebase-admin');
const functions = require('firebase-functions');
const images = require('./images.js');

const firebaseConfig = {
    keyFilename: 'google-services.json',
    projectId: 'com-project-id',
};

const firestore = firebase
    .initializeApp(firebaseConfig)

const bucket = firestore
    .storage()
    .bucket('com-my-bucket.appspot.com/')

exports.getImages = functions.https.onRequest((request, response) => {
    response.send(images.getImages(bucket))
})

images.js

module.exports = {
    getImages
}

const query = {
    directory: '/your-images-path'
};

function getImages(bucket) {
    bucket.getFiles(query).then(files => {
        return getUrls(files)
    }).catch(err => {
        console.error('Getting files:', err);
    });
}

function getUrls(files) {
    files.forEach(file => {
        file.getDownloadURL().then(url => {
            return url
        }).catch(err => {
            console.error('Downloading URL:', err);
        });
    })
}

  1. 执行firebase deploy以上传您的云功能
  2. Call您的应用程序中的自定义功能

答案 16 :(得分:0)

我正在使用AngularFire,并使用以下命令获取所有downloadURL

getPhotos(id: string): Observable<string[]> {
    const ref = this.storage.ref(`photos/${id}`)
    return ref.listAll().pipe(switchMap(list => {
      const calls: Promise<string>[] = [];
      list.items.forEach(item => calls.push(item.getDownloadURL()))
      return Promise.all(calls)
    }));
}

答案 17 :(得分:0)

结合这篇文章以及here的一些答案,并经过一些个人研究,对于使用打字稿的NodeJS,我设法使用firebase-admin做到了这一点:

import * as admin from 'firebase-admin';
const getFileNames = (folderName: any) => {
  admin.storage().bucket().getFiles(autoPaginate: false).then(([files]: any) => {
    const fileNames = files.map((file: any) => file.name);
    return fileNames;
  })
 }

就我而言,我还需要从Firebase存储中的特定文件夹中获取所有文件。根据{{​​3}},该文件夹不存在,而是一种命名约定。无论如何,我通过添加{ prefix: ${folderName}, autoPaginate: false }函数getFiles来做到这一点:

getFiles({ prefix: `${folderName}`, autoPaginate: false })

答案 18 :(得分:-1)

对于Android来说,最好的做法是使用FirebaseUI和Glide。

您需要将其添加到gradle / app中以获取库。请注意,它已经具有滑行功能!

implementation 'com.firebaseui:firebase-ui-storage:4.1.0'

然后在您的代码中使用

// Reference to an image file in Cloud Storage
StorageReference storageReference = FirebaseStorage.getInstance().getReference();

// ImageView in your Activity
ImageView imageView = findViewById(R.id.imageView);

// Download directly from StorageReference using Glide
// (See MyAppGlideModule for Loader registration)
GlideApp.with(this /* context */)
        .load(storageReference)
        .into(imageView);