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

Android Firebase Storage getFile()失败,生成0字节文件求助

Android SDK34下Firebase Storage getFile(Uri)下载失败问题分析

问题场景

在Android SDK34环境中,使用Firebase Storage从存储桶下载文件到共享下载文件夹时,调用StorageReference.getFile(Uri)会生成0字节文件后失败,但通过getBytes获取数据后自行写入文件的方式可以正常工作。

无法正常工作的代码

// This does not. See the exception details below
public void download(String remotePath, Uri localUri) {
  StorageReference fileRef = storageRef.child(remotePath);
  fileRef
  .getFile(localUri)
  .addOnFailureListener(
      error -> {
        System.out.println(error.getMessage());
      });
}

错误堆栈信息

error = {StorageException@26984} "com.google.firebase.storage.StorageException: An unknown error occurred, please check the HTTP result code and inner exception for server response."
 cause = {IOException@26987} "java.io.IOException: No such file or directory"
  backtrace = null
  cause = {IOException@26987} "java.io.IOException: No such file or directory"
   backtrace = null
   cause = {IOException@26987} "java.io.IOException: No such file or directory"
   detailMessage = "No such file or directory"
   stackTrace = {StackTraceElement[14]@26998} 
    0 = {StackTraceElement@27003} "java.io.UnixFileSystem.createFileExclusively0(Native Method)"
    1 = {StackTraceElement@27004} "java.io.UnixFileSystem.createFileExclusively(UnixFileSystem.java:349)"
    2 = {StackTraceElement@27005} "java.io.File.createNewFile(File.java:1006)"
    3 = {StackTraceElement@27006} "com.google.firebase.storage.FileDownloadTask.processResponse(FileDownloadTask.java:136)"
    4 = {StackTraceElement@27007} "com.google.firebase.storage.FileDownloadTask.run(FileDownloadTask.java:228)"
    5 = {StackTraceElement@27008} "com.google.firebase.storage.StorageTask.lambda$getRunnable$7$com-google-firebase-storage-StorageTask(StorageTask.java:1077)"
    6 = {StackTraceElement@27009} "com.google.firebase.storage.StorageTask$$ExternalSyntheticLambda7.run(Unknown Source:2)"
    7 = {StackTraceElement@27010} "com.google.firebase.concurrent.LimitedConcurrencyExecutor.lambda$decorate$0$com-google-firebase-concurrent-LimitedConcurrencyExecutor(LimitedConcurrencyExecutor.java:65)"
    8 = {StackTraceElement@27011} "com.google.firebase.concurrent.LimitedConcurrencyExecutor$$ExternalSyntheticLambda0.run(Unknown Source:4)"
    9 = {StackTraceElement@27012} "java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)"
    10 = {StackTraceElement@27013} "java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)"
    11 = {StackTraceElement@27014} "com.google.firebase.concurrent.CustomThreadFactory.lambda$newThread$0$com-google-firebase-concurrent-CustomThreadFactory(CustomThreadFactory.java:47)"
    12 = {StackTraceElement@27015} "com.google.firebase.concurrent.CustomThreadFactory$$ExternalSyntheticLambda0.run(Unknown Source:4)"
    13 = {StackTraceElement@27016} "java.lang.Thread.run(Thread.java:1012)"

可以正常工作的代码

public void download(String remotePath, Uri localUri) {
  StorageReference fileRef = storageRef.child(remotePath);
  fileRef
      .getBytes(1024 * 1024 * 16)
      .addOnSuccessListener(
          result -> {
            try {
              ContentResolver resolver = context.getContentResolver();
              OutputStream stream = resolver.openOutputStream(localUri);
              stream.write(result);
              stream.close();
            } catch (Exception e) {
              System.out.println(e.getMessage());
            }
          });
}

LocalUri创建代码

ContentResolver resolver = context.getContentResolver();
String fileName = UUID.randomUUID().toString().toUpperCase();
Uri imagesUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);

ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
values.put(MediaStore.MediaColumns.MIME_TYPE, "image/png");

Uri localUri = resolver.insert(imagesUri, values);

原因解析

  1. Firebase方法的局限性:StorageReference.getFile(Uri)内部会尝试将传入的Uri转换为本地文件路径,然后使用File.createNewFile()等文件系统API直接操作文件。但通过MediaStore.insert()生成的是内容Uri(content://开头),并非指向真实的本地文件路径,无法通过File类进行直接文件系统操作,因此抛出"No such file or directory"异常。

  2. 合规的共享存储操作:你使用ContentResolver.openOutputStream()写入数据的方式,是Android 10+分区存储规范推荐的操作方式。该方法通过内容Uri直接获取输出流,绕过了直接操作文件路径的限制,符合共享存储的访问规则,因此可以正常写入数据。

  3. 版本适配问题:Android SDK34严格执行分区存储规则,进一步限制了APP对外部存储文件路径的直接访问,这也导致Firebase旧的文件操作逻辑在新系统下失效。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 23:13:15