FirebaseStorage:如何删除目录
Posted
技术标签:
【中文标题】FirebaseStorage:如何删除目录【英文标题】:FirebaseStorage: How to Delete Directory 【发布时间】:2016-10-11 12:06:48 【问题描述】:当我尝试删除目录时,FirebaseStorage 总是返回错误 400
,即类似以下的内容总是返回错误 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 个文件)。
【问题讨论】:
【参考方案1】:从安全的谷歌云功能的上下文中 - 您可以使用谷歌云存储 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`);
);
更多文档可用on GCS API docs
【讨论】:
给我一个错误。试试const bucket = admin.storage().bucket();
,对我来说它有效。
这很有效,而且更容易实现。没有复杂的代码或任何东西。
Typescript Node.js 中的错误 require('@google-cloud/storage')() 不能是函数。
正如@TeodorCiuraru 指出的那样,如果您已经拥有firebase-admin
,则不需要@google-cloud/storage
!
googleapis.dev/nodejs/storage/latest/Bucket.html#deleteFiles【参考方案2】:
在 2020 年,删除 Firebase 存储文件夹似乎可行。我刚刚在下面的 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/`
);
【讨论】:
这真是太好了。但是超级慢。删除一个文件夹后的日志显示函数执行耗时 236960 毫秒,状态为“ok”。它还需要大量内存。我已将函数设置为使用最大运行时操作 const runtimeOpts = timeoutSeconds: 540, memory: '2GB' 这显示了通过管理 API 获取存储桶引用,并使用 GCS API 删除文件夹。问题是关于从 firebase 存储客户端 API 中删除文件。因此,虽然它可能对人们有用,但它并不能回答所提出的问题。【参考方案3】:来自 google 组,无法删除目录。您必须在某处(在 Firebase 数据库中)维护一个文件列表并一一删除。
https://groups.google.com/forum/#!topic/firebase-talk/aG7GSR7kVtw
我也提交了功能请求,但由于他们的错误跟踪器不公开,我无法分享链接。
【讨论】:
【参考方案4】:您可以列出文件夹并递归删除其内容:
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()
【讨论】:
您能否更新此代码以包含 deleteFile() 和 deleteFolderContents() 函数 @TomWalsh 完成。 deleteFolderContents 是递归思想。 谢谢,虽然我对 deleteFolderContents 感到特别困惑,但它的递归是什么意思。dir.prefixes
返回什么?
@TomWalsh deleteFolderContents 列出目录内容,删除其中的所有文件,并为找到的每个文件夹再次调用 deleteFolderContents。这就是递归的意思。关于前缀,您可以查看 firebase listAll 文档 (firebase.google.com/docs/reference/js/…)
@Miki 是的,它可能会删除文件夹/目录中的项目,但不会删除文件夹/目录。【参考方案5】:
执行此操作的方法可能如下(使用最后一个文件,去掉 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);
);
【讨论】:
如果您使用的是 Firebase 存储,您可能需要将rules_version = '2';
添加到您的 Firebase 规则中,否则 ref.listAll()
会失败【参考方案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 storage listAll()
方法目前在dev版包中,版本为5.0.0-dev.1
,如上图可以使用。
【讨论】:
【参考方案7】:根据 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/`
)
)
【讨论】:
【参考方案8】:在 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);
);
【讨论】:
【参考方案9】:这是使用 Firebase 函数删除 Firebase 存储文件夹中文件的一种解决方案。
假设您的 Firebase 数据库中的 /MyStorageFilesInDatabaseTrackedHere/path1/path2 下存储了模型。
这些模型将有一个名为“文件名”的字段,其中包含 Firebase 存储中文件的名称。
工作流程是:
-
删除 Firebase 数据库中包含模型列表的文件夹
通过 Firebase 函数监听该文件夹的删除
此函数将遍历文件夹的子文件夹,获取文件名并在存储中将其删除。
(免责声明: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);
);
【讨论】:
【参考方案10】:我注意到,在删除 firebase 存储文件夹中的所有文件时,过了一会儿,该文件夹也被删除了。无需任何操作。
【讨论】:
【参考方案11】:如上所述,删除目录是无效的。我正在分享一个查询 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)")
)
)
【讨论】:
【参考方案12】:看来删除目录的唯一办法就是循环遍历所有文件,一个一个地删除:
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');
【讨论】:
【参考方案13】:“Miki”答案的现代版本,使用 ES2018 Async/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)
如前所述,文件夹引用不会被删除,但至少它们不会像无法访问的文件那样从您的存储配额中拖出。
【讨论】:
虽然正确,但您正在处理系列中的所有文件。并行执行所有删除会很好。你可以使用 async/await 来做到这一点,但我建议将你的 async func 返回的所有 Promise 收集到一个数组中,并使用 Promise.all() 一次性处理它们。 ^ 是的,Promise.all
是你的朋友。【参考方案14】:
不要在家里这样做!
Firebase 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
【讨论】:
【参考方案15】:空文件夹会自行删除。所以从文件夹中删除所有文件也会删除文件夹本身。
【讨论】:
以上是关于FirebaseStorage:如何删除目录的主要内容,如果未能解决你的问题,请参考以下文章
svn如何删中文目录. 中文目录结构,UNICODE, 目录下建了(中文)文件.删除时路径无法解析.