Cloud Storage for Firebase 可讓您輕鬆快速地將檔案上傳到 已提供 Cloud Storage 個值區 並由 Firebase 管理
上傳檔案
如要上傳檔案到 Cloud Storage,請先建立指向 檔案的完整路徑,包括檔案名稱。
Kotlin+KTX
// Create a storage reference from our app val storageRef = storage.reference // Create a reference to "mountains.jpg" val mountainsRef = storageRef.child("mountains.jpg") // Create a reference to 'images/mountains.jpg' val mountainImagesRef = storageRef.child("images/mountains.jpg") // While the file names are the same, the references point to different files mountainsRef.name == mountainImagesRef.name // true mountainsRef.path == mountainImagesRef.path // false
Java
// Create a storage reference from our app StorageReference storageRef = storage.getReference(); // Create a reference to "mountains.jpg" StorageReference mountainsRef = storageRef.child("mountains.jpg"); // Create a reference to 'images/mountains.jpg' StorageReference mountainImagesRef = storageRef.child("images/mountains.jpg"); // While the file names are the same, the references point to different files mountainsRef.getName().equals(mountainImagesRef.getName()); // true mountainsRef.getPath().equals(mountainImagesRef.getPath()); // false
建立適當的參照後,請呼叫 putBytes()
。
putFile()
或 putStream()
方法,即可上傳檔案
至 Cloud Storage。
您無法上傳任何參照 Cloud Storage 個值區。參照項目必須指向子網址。
從記憶體中的資料上傳
putBytes()
方法是將檔案上傳至 Cloud Storage 最簡單的方式。putBytes()
會擷取 byte[]
並傳回
UploadTask
,用於管理及監控上傳狀態。
Kotlin+KTX
// Get the data from an ImageView as bytes imageView.isDrawingCacheEnabled = true imageView.buildDrawingCache() val bitmap = (imageView.drawable as BitmapDrawable).bitmap val baos = ByteArrayOutputStream() bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos) val data = baos.toByteArray() var uploadTask = mountainsRef.putBytes(data) uploadTask.addOnFailureListener { // Handle unsuccessful uploads }.addOnSuccessListener { taskSnapshot -> // taskSnapshot.metadata contains file metadata such as size, content-type, etc. // ... }
Java
// Get the data from an ImageView as bytes imageView.setDrawingCacheEnabled(true); imageView.buildDrawingCache(); Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos); byte[] data = baos.toByteArray(); UploadTask uploadTask = mountainsRef.putBytes(data); uploadTask.addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception exception) { // Handle unsuccessful uploads } }).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { // taskSnapshot.getMetadata() contains file metadata such as size, content-type, etc. // ... } });
由於 putBytes()
接受 byte[]
,因此應用程式必須保留整個
檔案內容建議使用 putStream()
或
putFile()
,即可減少記憶體。
從串流上傳
putStream()
是最適合用來上傳
將檔案複製到 Cloud Storage。putStream()
會接受 InputStream
並傳回
可用來管理及監控上傳狀態的 UploadTask
。
Kotlin+KTX
val stream = FileInputStream(File("path/to/images/rivers.jpg")) uploadTask = mountainsRef.putStream(stream) uploadTask.addOnFailureListener { // Handle unsuccessful uploads }.addOnSuccessListener { taskSnapshot -> // taskSnapshot.metadata contains file metadata such as size, content-type, etc. // ... }
Java
InputStream stream = new FileInputStream(new File("path/to/images/rivers.jpg")); uploadTask = mountainsRef.putStream(stream); uploadTask.addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception exception) { // Handle unsuccessful uploads } }).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { // taskSnapshot.getMetadata() contains file metadata such as size, content-type, etc. // ... } });
從本機檔案上傳
您可以上傳裝置上的本機檔案,例如
相機使用 putFile()
方法。putFile()
會取用 File
並傳回
UploadTask
,用於管理及監控上傳狀態。
Kotlin+KTX
var file = Uri.fromFile(File("path/to/images/rivers.jpg")) val riversRef = storageRef.child("images/${file.lastPathSegment}") uploadTask = riversRef.putFile(file) // Register observers to listen for when the download is done or if it fails uploadTask.addOnFailureListener { // Handle unsuccessful uploads }.addOnSuccessListener { taskSnapshot -> // taskSnapshot.metadata contains file metadata such as size, content-type, etc. // ... }
Java
Uri file = Uri.fromFile(new File("path/to/images/rivers.jpg")); StorageReference riversRef = storageRef.child("images/"+file.getLastPathSegment()); uploadTask = riversRef.putFile(file); // Register observers to listen for when the download is done or if it fails uploadTask.addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception exception) { // Handle unsuccessful uploads } }).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { // taskSnapshot.getMetadata() contains file metadata such as size, content-type, etc. // ... } });
取得下載網址
上傳檔案後,您可以呼叫
StorageReference
上的 getDownloadUrl()
方法:
Kotlin+KTX
val ref = storageRef.child("images/mountains.jpg") uploadTask = ref.putFile(file) val urlTask = uploadTask.continueWithTask { task -> if (!task.isSuccessful) { task.exception?.let { throw it } } ref.downloadUrl }.addOnCompleteListener { task -> if (task.isSuccessful) { val downloadUri = task.result } else { // Handle failures // ... } }
Java
final StorageReference ref = storageRef.child("images/mountains.jpg"); uploadTask = ref.putFile(file); Task<Uri> urlTask = uploadTask.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() { @Override public Task<Uri> then(@NonNull Task<UploadTask.TaskSnapshot> task) throws Exception { if (!task.isSuccessful()) { throw task.getException(); } // Continue with the task to get the download URL return ref.getDownloadUrl(); } }).addOnCompleteListener(new OnCompleteListener<Uri>() { @Override public void onComplete(@NonNull Task<Uri> task) { if (task.isSuccessful()) { Uri downloadUri = task.getResult(); } else { // Handle failures // ... } } });
新增檔案中繼資料
您也可以在上傳檔案時加入中繼資料。這項中繼資料包含一般檔案中繼資料屬性,例如 name
、size
、
和 contentType
(通常稱為 MIME 類型)。putFile()
方法
從 File
副檔名自動推論 MIME 類型,但您也可以
請在中繼資料中指定 contentType
,覆寫自動偵測的類型。如果
您並未提供 contentType
,而 Cloud Storage 無法推斷出
預設副檔名,Cloud Storage 會使用
application/octet-stream
。請參閱使用檔案中繼資料
一節,進一步瞭解檔案中繼資料。
Kotlin+KTX
// Create file metadata including the content type var metadata = storageMetadata { contentType = "image/jpg" } // Upload the file and metadata uploadTask = storageRef.child("images/mountains.jpg").putFile(file, metadata)
Java
// Create file metadata including the content type StorageMetadata metadata = new StorageMetadata.Builder() .setContentType("image/jpg") .build(); // Upload the file and metadata uploadTask = storageRef.child("images/mountains.jpg").putFile(file, metadata);
管理上傳項目
除了開始上傳之外,您還可以使用
pause()
、resume()
和 cancel()
方法。暫停及繼續活動
可分別引發 pause
和 progress
狀態變更。取消
上傳失敗並傳回錯誤
已取消上傳。
Kotlin+KTX
uploadTask = storageRef.child("images/mountains.jpg").putFile(file) // Pause the upload uploadTask.pause() // Resume the upload uploadTask.resume() // Cancel the upload uploadTask.cancel()
Java
uploadTask = storageRef.child("images/mountains.jpg").putFile(file); // Pause the upload uploadTask.pause(); // Resume the upload uploadTask.resume(); // Cancel the upload uploadTask.cancel();
監控上傳進度
您可以新增事件監聽器來處理成功、失敗、進度或暫停 上傳工作:
監聽器類型 | 一般用量 |
---|---|
OnProgressListener |
系統會在資料傳輸過程中定期呼叫這個事件監聽器,並用來填入上傳/下載指標。 |
OnPausedListener |
工作暫停時,系統就會呼叫此事件監聽器。 |
OnSuccessListener |
工作順利完成後,系統就會呼叫此事件監聽器。 |
OnFailureListener |
上傳失敗時,系統就會呼叫此事件監聽器。可能的原因包括網路逾時、授權失敗或是您取消工作。 |
OnFailureListener
會使用 Exception
例項呼叫。其他事件監聽器會使用 UploadTask.TaskSnapshot
物件呼叫。此物件是事件發生時的工作不可變動的檢視畫面。
UploadTask.TaskSnapshot
包含下列屬性:
屬性 | 類型 | 說明 |
---|---|---|
getDownloadUrl |
String |
可用來下載物件的網址。這個網址是可公開檢索的公開網址,可與其他客戶分享。上傳完成後,系統就會填入這個值。 |
getError |
Exception |
如果工作失敗,這會造成原因為「例外狀況」。 |
getBytesTransferred |
long |
擷取這個快照時已傳輸的位元組總數。 |
getTotalByteCount |
long |
預計上傳的位元組總數。 |
getUploadSessionUri |
String |
透過對 putFile 發出的其他呼叫,可用來繼續這項工作的 URI。 |
getMetadata |
StorageMetadata |
上傳完成之前,系統會將中繼資料傳送至伺服器。上傳完成後,這是伺服器傳回的中繼資料。 |
getTask |
UploadTask |
建立這張快照的工作。透過這項工作取消、暫停或繼續上傳作業。 |
getStorage |
StorageReference |
用來建立 UploadTask 的 StorageReference 。 |
UploadTask
事件監聽器提供簡單又強大的方式進行監控
上傳事件。
Kotlin+KTX
// Observe state change events such as progress, pause, and resume // You'll need to import com.google.firebase.storage.component1 and // com.google.firebase.storage.component2 uploadTask.addOnProgressListener { (bytesTransferred, totalByteCount) -> val progress = (100.0 * bytesTransferred) / totalByteCount Log.d(TAG, "Upload is $progress% done") }.addOnPausedListener { Log.d(TAG, "Upload is paused") }
Java
// Observe state change events such as progress, pause, and resume uploadTask.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() { @Override public void onProgress(UploadTask.TaskSnapshot taskSnapshot) { double progress = (100.0 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount(); Log.d(TAG, "Upload is " + progress + "% done"); } }).addOnPausedListener(new OnPausedListener<UploadTask.TaskSnapshot>() { @Override public void onPaused(UploadTask.TaskSnapshot taskSnapshot) { Log.d(TAG, "Upload is paused"); } });
處理活動生命週期變更
即使活動生命週期有所變更 (例如 例如簡報或旋轉畫面)。您附加的所有事件監聽器也會保留附加狀態。這可能會導致未預期的結果 。
如要解決這個問題,可以利用活動範圍訂閱事件監聽器
,在活動停止時自動取消註冊。接著,使用
getActiveUploadTasks
方法 (用於重新啟動活動以取得上傳工作)
仍在執行或最近完成的工作
下例示範了這項做法,並示範如何保存儲存空間 參照路徑。
Kotlin+KTX
override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) // If there's an upload in progress, save the reference so you can query it later outState.putString("reference", storageRef.toString()) } override fun onRestoreInstanceState(savedInstanceState: Bundle) { super.onRestoreInstanceState(savedInstanceState) // If there was an upload in progress, get its reference and create a new StorageReference val stringRef = savedInstanceState.getString("reference") ?: return storageRef = Firebase.storage.getReferenceFromUrl(stringRef) // Find all UploadTasks under this StorageReference (in this example, there should be one) val tasks = storageRef.activeUploadTasks if (tasks.size > 0) { // Get the task monitoring the upload val task = tasks[0] // Add new listeners to the task using an Activity scope task.addOnSuccessListener(this) { // Success! // ... } } }
Java
@Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // If there's an upload in progress, save the reference so you can query it later if (mStorageRef != null) { outState.putString("reference", mStorageRef.toString()); } } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); // If there was an upload in progress, get its reference and create a new StorageReference final String stringRef = savedInstanceState.getString("reference"); if (stringRef == null) { return; } mStorageRef = FirebaseStorage.getInstance().getReferenceFromUrl(stringRef); // Find all UploadTasks under this StorageReference (in this example, there should be one) List<UploadTask> tasks = mStorageRef.getActiveUploadTasks(); if (tasks.size() > 0) { // Get the task monitoring the upload UploadTask task = tasks.get(0); // Add new listeners to the task using an Activity scope task.addOnSuccessListener(this, new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot state) { // Success! // ... } }); } }
getActiveUploadTasks
會擷取位於以下位置及較低位置的所有進行中上傳工作
方便您處理多項工作。
在程序重新啟動時繼續上傳
如果程序關閉,所有進行中的上傳作業將會中斷。 不過,在程序重新啟動後,您就可以繼續執行 與伺服器上傳工作階段這樣不僅能節省時間和頻寬 從檔案開頭開始上傳
如要這麼做,請透過 putFile
開始上傳。在產生的 StorageTask
中,
呼叫 getUploadSessionUri
,並將產生的值儲存在永久儲存空間
(例如 SharedPreferences)。
Kotlin+KTX
uploadTask = storageRef.putFile(localFile) uploadTask.addOnProgressListener { taskSnapshot -> sessionUri = taskSnapshot.uploadSessionUri if (sessionUri != null && !saved) { saved = true // A persisted session has begun with the server. // Save this to persistent storage in case the process dies. } }
Java
uploadTask = mStorageRef.putFile(localFile); uploadTask.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() { @Override public void onProgress(UploadTask.TaskSnapshot taskSnapshot) { Uri sessionUri = taskSnapshot.getUploadSessionUri(); if (sessionUri != null && !mSaved) { mSaved = true; // A persisted session has begun with the server. // Save this to persistent storage in case the process dies. } } });
程序因上傳作業中斷而重新啟動後,請再次呼叫 putFile。但 這次也會傳遞已儲存的 URI
Kotlin+KTX
// resume the upload task from where it left off when the process died. // to do this, pass the sessionUri as the last parameter uploadTask = storageRef.putFile( localFile, storageMetadata { }, sessionUri, )
Java
//resume the upload task from where it left off when the process died. //to do this, pass the sessionUri as the last parameter uploadTask = mStorageRef.putFile(localFile, new StorageMetadata.Builder().build(), sessionUri);
上週的工作階段。如果您嘗試在工作階段到期後恢復工作階段,或工作階段發生錯誤,您會收到失敗的回呼。您有責任確保檔案在上傳後不會變更。
處理錯誤
導致上傳發生錯誤的原因有很多種,包括 本機檔案不存在,或使用者無權上傳 指定要上傳的檔案如要進一步瞭解錯誤,請參閱 處理錯誤 一節。
完整範例
含有進度監控和錯誤處理機制的完整上傳示例 如下所示:
Kotlin+KTX
// File or Blob file = Uri.fromFile(File("path/to/mountains.jpg")) // Create the file metadata metadata = storageMetadata { contentType = "image/jpeg" } // Upload file and metadata to the path 'images/mountains.jpg' uploadTask = storageRef.child("images/${file.lastPathSegment}").putFile(file, metadata) // Listen for state changes, errors, and completion of the upload. // You'll need to import com.google.firebase.storage.component1 and // com.google.firebase.storage.component2 uploadTask.addOnProgressListener { (bytesTransferred, totalByteCount) -> val progress = (100.0 * bytesTransferred) / totalByteCount Log.d(TAG, "Upload is $progress% done") }.addOnPausedListener { Log.d(TAG, "Upload is paused") }.addOnFailureListener { // Handle unsuccessful uploads }.addOnSuccessListener { // Handle successful uploads on complete // ... }
Java
// File or Blob file = Uri.fromFile(new File("path/to/mountains.jpg")); // Create the file metadata metadata = new StorageMetadata.Builder() .setContentType("image/jpeg") .build(); // Upload file and metadata to the path 'images/mountains.jpg' uploadTask = storageRef.child("images/"+file.getLastPathSegment()).putFile(file, metadata); // Listen for state changes, errors, and completion of the upload. uploadTask.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() { @Override public void onProgress(UploadTask.TaskSnapshot taskSnapshot) { double progress = (100.0 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount(); Log.d(TAG, "Upload is " + progress + "% done"); } }).addOnPausedListener(new OnPausedListener<UploadTask.TaskSnapshot>() { @Override public void onPaused(UploadTask.TaskSnapshot taskSnapshot) { Log.d(TAG, "Upload is paused"); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception exception) { // Handle unsuccessful uploads } }).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { // Handle successful uploads on complete // ... } });
上傳檔案後,我們接著來學習如何 下載 出發地:Cloud Storage。