You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中实现批量上传文件夹文件至Firebase Storage

批量上传SparseSpatialMap目录文件到Firebase Storage(Unity/C#)

你可以通过遍历目标目录下的所有文件,复用现有上传逻辑实现批量上传。以下是修改后的完整代码及关键说明:

using System.IO;
using System.Threading.Tasks;
using UnityEngine;
using Firebase.Storage;

public class FirebaseBatchUpload : MonoBehaviour
{
    FirebaseStorage storage;
    StorageReference storageReference;

    void Start()
    {
        UploadAllFilesInSparseSpatialMap();
    }

    void UploadAllFilesInSparseSpatialMap()
    {
        if (Permission.HasUserAuthorizedPermission(Permission.ExternalStorageRead))
        {
            Debug.Log("权限已获取");
            
            // 拼接目标目录完整路径
            string targetDirectory = Path.Combine(Application.persistentDataPath, "SparseSpatialMap");
            
            // 检查目录是否存在
            if (!Directory.Exists(targetDirectory))
            {
                Debug.LogError($"目录不存在:{targetDirectory}");
                return;
            }
            
            // 获取目录下所有文件(仅当前目录,如需包含子目录改为SearchOption.AllDirectories)
            string[] allFiles = Directory.GetFiles(targetDirectory, "*", SearchOption.TopDirectoryOnly);
            
            if (allFiles.Length == 0)
            {
                Debug.Log("目录下无文件");
                return;
            }

            // 初始化Firebase Storage引用
            storage = FirebaseStorage.DefaultInstance;
            storageReference = storage.GetReferenceFromUrl("gs://houdini-ac884.appspot.com");
            
            // 批量发起上传任务
            var uploadTasks = new Task<StorageMetadata>[allFiles.Length];
            for (int i = 0; i < allFiles.Length; i++)
            {
                uploadTasks[i] = UploadSingleFile(allFiles[i]);
            }

            // 等待所有上传任务完成
            Task.WhenAll(uploadTasks).ContinueWith(task =>
            {
                if (task.IsFaulted)
                {
                    Debug.LogError("部分文件上传失败:" + task.Exception.ToString());
                }
                else
                {
                    Debug.Log("所有文件上传完成");
                }
            });
        }
        else
        {
            Debug.Log("未获取权限,请求权限中");
            Permission.RequestUserPermission(Permission.ExternalStorageRead);
        }
    }

    /// <summary>
    /// 复用的单文件上传方法
    /// </summary>
    Task<StorageMetadata> UploadSingleFile(string localFilePath)
    {
        // 提取文件名,作为Firebase存储路径的一部分
        string fileName = Path.GetFileName(localFilePath);
        StorageReference fileRef = storageReference.Child($"uploads/{fileName}");

        // 用二进制流读取文件,适配所有文件类型
        using (FileStream stream = File.OpenRead(localFilePath))
        {
            return fileRef.PutStreamAsync(stream).ContinueWith(task =>
            {
                if (task.IsFaulted || task.IsCanceled)
                {
                    Debug.LogError($"上传失败 {localFilePath}:{task.Exception.ToString()}");
                    throw task.Exception;
                }
                else
                {
                    StorageMetadata metadata = task.Result;
                    Debug.Log($"上传完成:{fileName} | MD5哈希:{metadata.Md5Hash}");
                    return metadata;
                }
            });
        }
    }
}

关键改动说明

  • 目录遍历:通过Directory.GetFiles获取目标目录下所有文件,可通过SearchOption参数控制是否包含子目录。
  • 文件流优化:改用File.OpenRead获取二进制流,避免StreamReader仅适配文本文件的局限,兼容所有文件类型。
  • 批量任务管理:用Task.WhenAll统一等待全部上传任务完成,方便批量处理结果。
  • 动态存储路径:保留原文件名作为Firebase存储路径的一部分,避免文件名冲突。
  • 错误防护:新增目录存在性、空文件检查,单个文件上传失败时单独记录日志,不影响其他文件上传。

可选扩展

如果需要保留原目录结构(比如子目录文件上传到Firebase对应路径),可以计算文件相对路径替换fileName:

// 计算文件相对于目标目录的路径
string relativePath = Path.GetRelativePath(targetDirectory, localFilePath);
// 替换路径分隔符为Firebase兼容的斜杠
relativePath = relativePath.Replace('\\', '/');
StorageReference fileRef = storageReference.Child($"uploads/{relativePath}");

内容的提问来源于stack exchange,提问作者EvocativeAxis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 22:40:44