在 Flutter 中使用 Cloud Storage 上傳檔案

您可以使用 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) {
  // ...
}

上傳原始資料

如果上傳字串或 File 不切實際,您可以使用 Uint8List 的形式上傳較低層級的型別資料。在這種情況下,請使用資料呼叫 putData() 方法:

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

取得下載網址

上傳檔案後,您可以呼叫 Reference 上的 getDownloadUrl() 方法,取得下載檔案的網址:

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 下載檔案