向 Cloud Storage 上传文件 (Flutter)

Cloud Storage for Firebase 可让您快速轻松地将文件上传到 Firebase 提供和管理的 Cloud Storage 存储桶中。

上传文件

如需将文件上传到 Cloud Storage,首先要创建对文件的完整路径(包括文件名)的引用。

// Create a storage reference from our app
final storageRef = FirebaseStorage.instance.ref();

// Create a reference to "mountains.jpg"
final mountainsRef = storageRef.child("mountains.jpg");

// Create a reference to 'images/mountains.jpg'
final mountainImagesRef = storageRef.child("images/mountains.jpg");

// While the file names are the same, the references point to different files
assert(mountainsRef.name == mountainImagesRef.name);
assert(mountainsRef.fullPath != mountainImagesRef.fullPath);

创建适当的引用后,您可以调用 putFile()putString()putData() 方法将文件上传到 Cloud Storage。

您无法通过指向 Cloud Storage 存储桶根目录的引用来上传数据。您的引用必须指向一个子网址。

通过文件上传

如需上传文件,您必须先获取其设备端位置的绝对路径。例如,如果某个文件存在于应用的文档目录中,请使用官方的 path_provider 软件包生成文件路径并将其传递给 putFile()

Directory appDocDir = await getApplicationDocumentsDirectory();
String filePath = '${appDocDir.absolute}/file-to-upload.png';
File file = File(filePath);

try {
  await mountainsRef.putFile(file);
} on firebase_core.FirebaseException catch (e) {
  // ...
}

通过字符串上传

您可以使用 putString() 方法以原始字符串或 base64base64urldata_url 编码字符串形式上传数据。例如,如需上传编码为数据网址的文本字符串,请使用以下代码:

String dataUrl = 'data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==';

try {
  await mountainsRef.putString(dataUrl, format: PutStringFormat.dataUrl);
} on FirebaseException catch (e) {
  // ...
}

上传原始数据

对于不便上传字符串或文件的情况,您可以采用 Uint8List 的形式上传较低级类型的数据。在这种情况下,请使用您的数据调用 putData() 方法:

try {
  // Upload raw data.
  await mountainsRef.putData(data);
} on firebase_core.FirebaseException catch (e) {
  // ...
}

获取下载网址

上传文件后,您可以调用 ReferencegetDownloadUrl() 方法,获取下载文件的网址:

await mountainsRef.getDownloadURL();

添加文件元数据

在上传文件时,您还可以包含元数据。这些元数据包含典型的文件元数据属性,如 contentType(通常称为 MIME 类型)。putFile() 方法会自动根据 File 扩展名推断 MIME 类型,您也可以在元数据中指定 contentType,覆盖自动检测到的类型。如果您未提供 contentType,并且 Cloud Storage 无法根据文件扩展名推断出默认值,Cloud Storage 将使用 application/octet-stream。请参阅使用文件元数据

try {
  await mountainsRef.putFile(file, SettableMetadata(
    contentType: "image/jpeg",
  ));
} on firebase_core.FirebaseException catch (e) {
  // ...
}

管理上传

除了启动上传外,您还可以分别使用 pause()resume()cancel() 方法来暂停、恢复和取消上传。暂停和恢复事件会分别导致状态变为 pauseprogress。取消上传会导致上传失败,并显示一条错误指明上传已被取消。

final task = mountainsRef.putFile(largeFile);

// Pause the upload.
bool paused = await task.pause();
print('paused, $paused');

// Resume the upload.
bool resumed = await task.resume();
print('resumed, $resumed');

// Cancel the upload.
bool canceled = await task.cancel();
print('canceled, $canceled');

监控上传进度

您可以监听任务的事件流来处理上传任务中的成功、失败、进度或暂停等各种情况:

事件类型 典型用法
TaskState.running 在数据传输期间定期触发,可用于为上传/下载进度指示器提供显示数据。
TaskState.paused 在任务每次暂停时触发。
TaskState.success 在任务成功完成时触发。
TaskState.canceled 在任务每次取消时触发。
TaskState.error 在上传失败时触发。网络超时、授权失败或取消任务时会发生此事件。
mountainsRef.putFile(file).snapshotEvents.listen((taskSnapshot) {
  switch (taskSnapshot.state) {
    case TaskState.running:
      // ...
      break;
    case TaskState.paused:
      // ...
      break;
    case TaskState.success:
      // ...
      break;
    case TaskState.canceled:
      // ...
      break;
    case TaskState.error:
      // ...
      break;
  }
});

错误处理

导致上传时出错的原因有很多,包括本地文件不存在,或者用户不具备上传相应文件的权限。如需了解错误详情,请参阅相关文档的处理错误部分。

完整示例

下面是一个包含进度监控和错误处理的完整上传示例:

final appDocDir = await getApplicationDocumentsDirectory();
final filePath = "${appDocDir.absolute}/path/to/mountains.jpg";
final file = File(filePath);

// Create the file metadata
final metadata = SettableMetadata(contentType: "image/jpeg");

// Create a reference to the Firebase Storage bucket
final storageRef = FirebaseStorage.instance.ref();

// Upload file and metadata to the path 'images/mountains.jpg'
final uploadTask = storageRef
    .child("images/path/to/mountains.jpg")
    .putFile(file, metadata);

// Listen for state changes, errors, and completion of the upload.
uploadTask.snapshotEvents.listen((TaskSnapshot taskSnapshot) {
  switch (taskSnapshot.state) {
    case TaskState.running:
      final progress =
          100.0 * (taskSnapshot.bytesTransferred / taskSnapshot.totalBytes);
      print("Upload is $progress% complete.");
      break;
    case TaskState.paused:
      print("Upload is paused.");
      break;
    case TaskState.canceled:
      print("Upload was canceled");
      break;
    case TaskState.error:
      // Handle unsuccessful uploads
      break;
    case TaskState.success:
      // Handle successful uploads on complete
      // ...
      break;
  }
});

现在您已经上传了文件,接下来,我们将学习如何从 Cloud Storage 中下载文件