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

Lui*_*roa 87 firebase firebase-storage

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

Fra*_*len 90

Firebase存储中目前没有API调用来列出文件夹中的所有文件.如果需要此类功能,则应将文件的元数据(例如下载URL)存储在可以列出的位置.在火力地堡实时数据库是为这个完美的,并允许您亦可轻松与他人分享的网址.

您可以在我们的FriendlyPix示例应用程序中找到一个好的(但有些参与)样本.Web版本的相关代码在这里,但也有iOS和Android版本.

  • 如果我需要在Realtime Database中保留所有存储文件的URL,那么在Storage中拥有文件夹层次结构的目的是什么?所有具有唯一名称的文件都可以存储在同一级别,完全不需要文件夹!你看,这是一个矛盾!基本上,文件夹层次结构背后的主要原理是通配符查询,而不事先知道您在文件夹中拥有的内容,而您没有合理地提供这些内容. (41认同)
  • 现在呢 ?2018年有没有直接的API? (9认同)
  • 你打算在Firebase上实现这个吗? (7认同)
  • Firebase存储基于Google云端存储,它完全符合您的要求:它将所有对象存储在一个长列表中.Firebase存储模型构建了一个层次结构,无可否认是一个漏洞抽象.在Firebase存储中使用文件夹的常见原因是逻辑数据分离以及基于文件夹结构制定安全规则. (6认同)
  • 如果用户连接在上传后和将downloadUrl保存到数据库之前丢失会发生什么?在这种情况下,我们如何发现文件夹中的现有文件? (6认同)

joh*_*bay 31

自2017年3月起:随着Firebase云功能的增加,以及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);
      });
    });

  });

});
Run Code Online (Sandbox Code Playgroud)

我希望这会给你一般的想法.有关更好的云功能示例,请查看Google的Github repo,其中包含Firebase的Cloud Functions示例.另请查看他们的Google Cloud Node API文档

  • 这太愚蠢了,firebase不只是将这个api添加到firebase sdk中 (30认同)
  • @Thaina我认为这与规模有关.他们不仅要考虑小型应用,还要考虑巨头.如果路径有数千个文件怎么办?此操作将消耗大量计算能力,并且必须为每个看似无辜且简单的调用引用数据库.我越大越深入地使用firebase,我就越了解为什么会做出某些妥协. (3认同)

Ros*_*des 22

截至2019年5月,适用于Cloud Storage的Firebase SDK 版本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
  });
}
Run Code Online (Sandbox Code Playgroud)

注意,要使用此功能,您必须选择加入“安全规则”的第2版,这可以通过制作rules_version = '2';安全规则的第一行来完成:

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
Run Code Online (Sandbox Code Playgroud)

我建议检查文档以获取更多参考。

同样,根据setup,在步骤5上,此脚本不允许使用,Node.js因为它require("firebase/app");不会firebase.storage()作为函数返回。这只能通过使用来实现import * as firebase from 'firebase/app';


Mik*_*ald 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]()
Run Code Online (Sandbox Code Playgroud)

上传:

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)
}
Run Code Online (Sandbox Code Playgroud)

下载:

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)
  })
})
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅零到应用程序:使用Firebase进行开发,以及它的相关源代码,以获取有关如何执行此操作的实际示例.

  • 但是如何使用Cloud Firestore获得相同的结果?) (2认同)

Ber*_*rci 10

结合这篇文章和这里的一些答案,经过一些个人研究,对于带有打字稿的 NodeJS,我设法通过使用以下方法来完成此任务firebase-admin

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

就我而言,我还需要从 firebase 存储中获取特定文件夹内的所有文件。根据谷歌存储,这些文件夹不存在,而是一种命名约定。{ prefix: ${folderName}, autoPaginate: false }无论如何,我通过在函数调用中添加以下内容来设法做到这一点(无需将每个文件的完整路径保存到数据库中)getFiles

...
const getFileNames = (folderName: string) => {
  admin.storage().bucket().getFiles({ prefix: `${folderName}`, autoPaginate: false })
    .then(([files]: any) => {
    ...
Run Code Online (Sandbox Code Playgroud)


小智 5

一种解决方法是创建一个内部没有任何内容的文件(即 list.txt),在此文件中,您可以使用所有文件 URL 的列表设置自定义元数据(即 Map<String, String>)。
因此,如果您需要下载 fodler 中的所有文件,您首先下载 list.txt 文件的元数据,然后遍历自定义数据并下载带有 Map 中 URL 的所有文件。

  • 是的,这是一种解决方法,但无法处理对单个 list.txt 的并发写入 (4认同)

小智 5

我在做我的项目时也遇到了这个问题。我真的希望他们提供一个结束 api 方法。无论如何,我就是这样做的:当您将图像上传到 Firebase 存储时,创建一个对象并将该对象同时传递到 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);
        }
    });
Run Code Online (Sandbox Code Playgroud)

稍后当您想要从文件夹下载图像时,您只需遍历该文件夹下的文件。此文件夹与 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) {

        }
    });
Run Code Online (Sandbox Code Playgroud)

现在我有一个包含每个图像的 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;
}
Run Code Online (Sandbox Code Playgroud)

这将返回一个位图列表,当它完成时,我只需将它们附加到主活动中的 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我必须先等待返回列表图像,然后再调用线程来处理列表位图。在这种情况下,图像包含 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);
}
Run Code Online (Sandbox Code Playgroud)

希望有人觉得它有帮助。它也将成为我未来的行会路线。


Ole*_*leg 5

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

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
        });
    });
});
Run Code Online (Sandbox Code Playgroud)

完整代码在这里:https : //gist.github.com/bossly/fb03686f2cb1699c2717a0359880cf84


tua*_*anh 5

对于节点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);
  });
Run Code Online (Sandbox Code Playgroud)


小智 5

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

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

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