37

400当我尝试删除目录时,FirebaseStorage 总是返回错误,即类似下面的内容总是返回错误400

let storageRef = FIRStorage.storage().reference().child("path/to/directory")
storageRef.deleteWithCompletion { (error) in
    print("error: \(error)") // always prints error code 400
}

但是,删除文件可以正常工作,例如不会返回错误:

let storageRef = FIRStorage.storage().reference().child("path/to/file.jpg")
storageRef.deleteWithCompletion { (error) in
    print("error: \(error)") // works fine, error is nil
}

我在这里做错了什么?我不认为 FirebaseStorage 不支持它,因为从目录中逐个删除文件会很糟糕(特别是如果所述目录有 100 或 1000 个这些文件)。

4

15 回答 15

32

从安全的谷歌云功能的上下文中 - 您可以使用谷歌云存储 npm 包(又名谷歌云存储 API)删除整个目录,如下所示:

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

  return bucket.deleteFiles({
    prefix: `users/${userId}/`
  }, function(err) {
    if (err) {
      console.log(err);
    } else {
      console.log(`All the Firebase Storage files in users/${userId}/ have been deleted`);
    }
  });

有关 GCS API 文档的更多文档

于 2018-04-04T23:23:14.483 回答
24

在 2020 年,删除 Firebase Storage 文件夹似乎可行。我刚刚在下面的 Cloud Functions (Node.js Admin) 中删除了文件夹、子文件夹和其中的文件。我确实使用 npm 下载了 Google Cloud Storage,但我并没有以物理方式导入该库,而且 Firebase Storage 现在似乎支持此功能,这与上面每个人所说的不同。也许他们已经更新了它。我测试了它,它正在工作。

admin.initializeApp({
    storageBucket: "bucket_name.appspot.com",
})

const bucket = admin.storage().bucket();
await bucket.deleteFiles({
   prefix: `${folderName}/`
});
于 2020-04-02T18:22:55.557 回答
17

从谷歌组,删除目录是不可能的。您必须在某处(在 Firebase 数据库中)维护文件列表并一一删除它们。

https://groups.google.com/forum/#!topic/firebase-talk/aG7GSR7kVtw

我也提交了功能请求,但由于他们的错误跟踪器不是公开的,所以我没有可以分享的链接。

于 2016-06-10T22:20:38.697 回答
15

您可以列出文件夹并递归删除其内容:

deleteFolder(path) {
  const ref = firebase.storage().ref(path);
  ref.listAll()
    .then(dir => {
      dir.items.forEach(fileRef => this.deleteFile(ref.fullPath, fileRef.name));
      dir.prefixes.forEach(folderRef => this.deleteFolder(folderRef.fullPath))
    })
    .catch(error => console.log(error));
}

deleteFile(pathToFile, fileName) {
  const ref = firebase.storage().ref(pathToFile);
  const childRef = ref.child(fileName);
  childRef.delete()
}
于 2019-07-02T01:23:18.167 回答
6

执行此操作的方法可能如下(使用最后一个文件,去掉 dir):

let ref = firebase.storage().ref(path);
ref.listAll().then(dir => {
  dir.items.forEach(fileRef => {
    var dirRef = firebase.storage().ref(fileRef.fullPath);
    dirRef.getDownloadURL().then(function(url) {
      var imgRef = firebase.storage().refFromURL(url);
      imgRef.delete().then(function() {
        // File deleted successfully 
      }).catch(function(error) {
        // There has been an error      
      });
    });
  });
}).catch(error => {
  console.log(error);
});
于 2020-01-15T09:29:18.383 回答
6

现在您知道我们无法删除 Firebase 存储中的文件夹。但是您可以列出该文件夹中的文件并删除每个文件。

这里有一个样本..

        // Create a root reference
        var storageRef = firebase.storage().ref();
        // Create a reference 
        var mountainsRef = storageRef.child("your root path");

        // Now we get the references of these files
        mountainsRef.listAll().then(function (result) {
            result.items.forEach(function (file) {
               file.delete();
            });
        }).catch(function (error) {
            // Handle any errors
        });

Flutter firebase 存储listAll()方式目前在 dev 版本的包中,在 version5.0.0-dev.1中,可以使用如上图。

于 2020-04-28T10:43:43.667 回答
5

根据TheFastCat的回答和Teodor Ciuraru的评论,我创建了下面的 Firebase 云函数,当用户从 Firebase 身份验证中删除时,它会删除用户的文件夹。

const admin = require('firebase-admin')
const functions = require('firebase-functions')

const bucket = admin.storage().bucket()

exports.deleteUser = functions.auth.user().onDelete(async (user) => {
    const { uid } = user
    await bucket.deleteFiles({
        prefix: `${uid}/`
    })
})
于 2020-03-12T15:27:20.630 回答
1

在 26/5/2017 没有办法删除目录但是你可以使用我的算法

使用此代码。

   this.sliders = this.db.list(`users/${this.USER_UID}/website/sliders`) as FirebaseListObservable<Slider[]>



  /**
   * Delete image from firebase storage is take a string path of the image
   * @param _image_path
   */
  deleteImage(_image_path: string) {

    // first delete the image
    const storageRef = firebase.storage().ref();
    const imageRef = storageRef.child(_image_path);
    imageRef.delete().then(function() {
      console.log('file deleted');
      // File deleted successfully
    }).catch(function(error) {
      // Uh-oh, an error occurred!
      console.log(error);
    });

  }



  /**
   * Deletes multiple Sliders, it takes an array of ids
   * @param ids
   */
  deleteMutipleSliders(ids: any) {

    ids.forEach(id => {

      this.getSliderDetails(id).subscribe(slider => {

        let id = slider.$key; // i think this is not nesesery
        const imgPath = slider.path;

        this.deleteImage(imgPath);
      });

      return this.sliders.remove(id);

    });


  }
于 2017-05-26T09:53:40.747 回答
1

我注意到,在删除 firebase 存储文件夹中的所有文件时,过了一会儿,该文件夹也被删除了。无需采取任何行动。

于 2021-01-14T07:53:03.800 回答
1

这是使用 Firebase 函数删除 Firebase 存储文件夹中文件的一种解决方案。

它假定您在 Firebase 数据库中的 /MyStorageFilesInDatabaseTrackedHere/path1/path2 下存储了模型。

这些模型将有一个名为“文件名”的字段,该字段将具有 Firebase 存储中文件的名称。

工作流程是:

  1. 删除 Firebase 数据库中包含模型列表的文件夹
  2. 通过 Firebase 函数监听该文件夹的删除
  3. 此函数将遍历文件夹的子文件夹,获取文件名并在 Storage 中将其删除。

(免责声明:Storage 中的文件夹在此函数结束时仍然存在,因此需要再次调用才能将其删除。)

// 1. Define your Firebase Function to listen for deletions on your path
exports.myFilesDeleted = functions.database
    .ref('/MyStorageFilesInDatabaseTrackedHere/{dbpath1}/{dbpath2}')
    .onDelete((change, context) => {

// 2. Create an empty array that you will populate with promises later
var allPromises = [];

// 3. Define the root path to the folder containing files
// You will append the file name later
var photoPathInStorageRoot = '/MyStorageTopLevelFolder/' + context.params.dbpath1 + "/" + context.params.dbpath2;

// 4. Get a reference to your Firebase Storage bucket
var fbBucket = admin.storage().bucket();

// 5. "change" is the snapshot containing all the changed data from your
// Firebase Database folder containing your models. Each child has a model
// containing your file filename
if (change.hasChildren()) {
    change.forEach(snapshot => {

        // 6. Get the filename from the model and
        // form the fully qualified path to your file in Storage
        var filenameInStorage = photoPathInStorageRoot + "/" + snapshot.val().filename;

        // 7. Create reference to that file in the bucket
        var fbBucketPath = fbBucket.file(filenameInStorage);

        // 8. Create a promise to delete the file and add it to the array
        allPromises.push(fbBucketPath.delete());
    });
}

// 9. Resolve all the promises (i.e. delete all the files in Storage)
return Promise.all(allPromises);
});
于 2018-09-30T18:14:22.827 回答
0

空文件夹会自行删除。因此,从文件夹中删除所有文件也会删除文件夹本身。

于 2022-01-17T23:30:48.893 回答
0

如上所述,删除目录是无效的。我正在分享一个查询 Firebase 数据库中文件列表并一一删除的示例。这是我的查询和电话。

    let messagePhotoQuery = messagesRef.child(group.key).child("messages").queryOrdered(byChild: "photoURL")
    deleteMessagePhotos(from: messagePhotoQuery)

这是我的函数循环获取 URL,然后删除该存储引用处的文件。

    func deleteMessagePhotos(from photoQuery: FIRDatabaseQuery) {
    photoQuery.observeSingleEvent(of: .value, with: { (messagesSnapshot) in
        guard messagesSnapshot.exists() else { return }
        print(messagesSnapshot)
        for message in messagesSnapshot.children {
            let messageSnapshot = message as! FIRDataSnapshot
            let messageData = messageSnapshot.value as! [String: AnyObject]
            if let photoURL = messageData["photoURL"] as? String {
                let photoStorageRef = FIRStorage.storage().reference(forURL: photoURL)
                photoStorageRef.delete(completion: { (error) in
                    if let error = error {
                        print(error)
                    } else {
                        // success
                        print("deleted \(photoURL)")
                    }
                })
            }
        }
    })
}
于 2017-08-23T14:48:36.840 回答
0

'Miki' 答案的现代版本,使用ES2018Async/Await删除文件计数器for await... of..

const storage = firebase.storage();

const deleteFile = async (filePath) => {
    const ref = storage.ref(filePath);
    return await ref.delete();
};
const deleteFolderRecursive = async (folderPath) => {
    const ref = storage.ref(folderPath);
    const list = await ref.listAll();
    let filesDeleted = 0;

    for await (const fileRef of list.items) {
        await deleteFile(fileRef.fullPath);
        filesDeleted++;
    }
    for await (const folderRef of list.prefixes) {
        filesDeleted += await deleteFolderRecursive(folderRef.fullPath);
    }
    return filesDeleted;
};

// Usage
async deleteFolder(x) {
    try {
         const filesDeleted = deleteFolderRecursive('path/to/storage/folder');
         console.log(`${filesDeleted} files has been deleted`);
         // you can now, for instance, unblock the UI at this point
    } catch(err){
       // probably denied permissions or 'path/to/storage/folder' is not a folder
       console.error(err)
    }

}

如前所述,文件夹引用不会被删除,但至少它们不会像无法访问的文件那样从您的存储配额中拖出。

于 2020-03-01T19:26:55.223 回答
0

看来删除目录的唯一方法就是循环遍历所有文件,一个一个地删除:

async function DeleteFirebaseStorageFolder(directoryName: string) {
    const serviceAccount = require('../secret/adminSdkPrivateKey.json');

    admin.initializeApp({
        credential: admin.credential.cert(serviceAccount),
        storageBucket: 'gs://yourprojectname.appspot.com'
    });

    const bucket = admin.storage().bucket();
    const files = (await bucket.getFiles({ directory: folderName }))[0];

    const Deletions = [];

    files.forEach(file => {
        Deletions.push(bucket.file(file.name).delete());
    })

    await Promise.all(Deletions);

    bucket.getFiles({ directory: folderName }).then((files) => {
        console.log('Remaining number of files: ' + (files[0].length).toString());
    })
}
DeleteFirebaseStorageFolder('myDirectoryName');
于 2018-11-20T17:58:48.743 回答
0

不要在家里这样做!

火力基地 9

示例如何使用客户端删除文件夹:

  • 如果有数百万个文件,不推荐可能不起作用。
async function deleteFolder(path: string) {
    const folderRef = ref(storage, path)
    const fileList = await listAll(folderRef)
    const promises = []
    for(let item of fileList.items) {
        promises.push(deleteObject(item))
    }
    const result = await Promise.all(promises)
    return result
}
于 2021-11-30T12:45:42.603 回答