本頁面由 Cloud Translation API 翻譯而成。
Switch to English

在Android上上傳文件

借助Cloud Storage,開發人員可以快速輕鬆地將文件上傳到Firebase提供和管理的Google Cloud Storage存儲桶。

上傳文件

要將文件上傳到Cloud Storage,首先要創建對文件完整路徑(包括文件名)的引用。

爪哇

// 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

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

一旦創建了適當的引用,就可以調用putBytes()putFile()putStream()方法將文件上傳到Cloud Storage。

您無法上傳引用Google Cloud Storage存儲桶根目錄的數據。您的引用必須指向子URL。

從內存中的數據上傳

putBytes()方法是將文件上傳到Cloud Storage的最簡單方法。 putBytes()取一個byte[]並返回一個UploadTask ,可用於管理和監視上傳狀態。

爪哇

// 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.
        // ...
    }
});

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.
    // ...
}

由於putBytes()接受byte[] ,因此它要求您的應用一次將文件的全部內容保存在內存中。考慮使用putStream()putFile()減少內存。

從流上傳

putStream()方法是將文件上傳到Cloud Storage的最通用的方法。 putStream()接受InputStream並返回一個UploadTask ,可用於管理和監視上傳狀態。

爪哇

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.
        // ...
    }
});

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.
    // ...
}

從本地文件上傳

您可以使用putFile()方法在設備上上傳本地文件,例如相機中的照片和視頻。 putFile()接收一個File並返回一個UploadTask ,您可以使用它來管理和監視上載的狀態。

爪哇

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.
        // ...
    }
});

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.
    // ...
}

獲取下載網址

上載文件之後,可以通過調用StorageReference上的getDownloadUrl()方法來獲取下載文件的URL:

爪哇

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
            // ...
        }
    }
});

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
        // ...
    }
}

添加文件元數據

您還可以在上傳文件時包括元數據。此元數據包含典型的文件元數據屬性,例如namesizecontentType (通常稱為MIME類型)。 putFile()方法自動從File擴展名推斷MIME類型,但是您可以通過在元數據中指定contentType來覆蓋自動檢測的類型。如果不提供contentType並且Cloud Storage無法從文件擴展名推斷默認值,則Cloud Storage使用application/octet-stream 。有關文件元數據的更多信息,請參見“ 使用文件元數據”部分。

爪哇

// 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);

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)

管理上傳

除了開始上傳外,您還可以使用pause()resume()cancel()方法暫停,繼續和取消上傳。暫停和恢復事件分別引起pauseprogress狀態更改。取消上載會導致上載失敗,並顯示一個錯誤,指示上載已被取消。

爪哇

uploadTask = storageRef.child("images/mountains.jpg").putFile(file);

// Pause the upload
uploadTask.pause();

// Resume the upload
uploadTask.resume();

// Cancel the upload
uploadTask.cancel();

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()

監控上傳進度

您可以添加偵聽器來處理上傳任務中的成功,失敗,進度或暫停:

偵聽器類型典型用法
OnProgressListener 數據傳輸時會定期調用此偵聽器,該偵聽器可用於填充上載/下載指示器。
OnPausedListener 每當任務暫停時,都會調用此偵聽器。
OnSuccessListener 任務成功完成後,將調用此偵聽器。
OnFailureListener 上載失敗時,都會調用此偵聽器。這可能是由於網絡超時,授權失敗或您取消任務而發生的。

使用Exception實例調用OnFailureListener 。其他偵聽器通過UploadTask.TaskSnapshot對象調用。該對像是事件發生時任務的不變視圖。 UploadTask.TaskSnapshot包含以下屬性:

屬性類型描述
getDownloadUrl String 可用於下載對象的URL。這是一個公共的,不可猜測的URL,可以與其他客戶端共享。上傳完成後,將填充此值。
getError Exception 如果任務失敗,則將其作為異常原因。
getBytesTransferred long 拍攝此快照時已傳輸的字節總數。
getTotalByteCount long 預期要上載的字節總數。
getUploadSessionUri String 一個URI,可通過另一個對putFile的調用來繼續執行此任務。
getMetadata StorageMetadata 上傳完成之前,這是將元數據發送到服務器。上傳完成後,這就是服務器返回的元數據。
getTask UploadTask 創建此快照的任務。使用此任務可以取消,暫停或繼續上載。
getStorage StorageReference 用於創建UploadTaskStorageReference

UploadTask事件偵聽器提供了一種監視上載事件的簡單而強大的方法。

爪哇

// 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");
    }
});

Kotlin + KTX

// Observe state change events such as progress, pause, and resume
// You'll need to import com.google.firebase.storage.ktx.component1 and 
// com.google.firebase.storage.ktx.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")
}

處理活動生命週期更改

即使活動生命週期發生了變化(例如,顯示對話框或旋轉屏幕),上傳仍會在後台繼續進行。您已附加的所有偵聽器也將保持附加狀態。如果在活動停止後調用它們,可能會導致意外結果。

您可以通過在活動範圍內訂閱偵聽器以在活動停止時自動註銷他們來解決此問題。然後,在活動重新啟動時使用getActiveUploadTasks方法來獲取仍在運行或最近完成的上載任務。

下面的示例演示了這一點,還顯示瞭如何持久使用所使用的存儲引用路徑。

爪哇

@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!
                // ...
            }
        });
    }
}

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!
            // ...
        }
    }
}

getActiveUploadTasks在提供的參考資料及其下方檢索所有活動的上傳任務,因此您可能需要處理多個任務。

在整個過程中繼續上載重新啟動

如果您的進程被關閉,所有正在進行的上傳將被中斷。但是,一旦進程重新啟動,您可以通過恢復與服務器的上傳會話來繼續上傳。通過不從文件開頭開始上載,可以節省時間和帶寬。

為此,請開始通過putFile上傳。在生成的StorageTask ,調用getUploadSessionUri並將生成的值保存在持久存儲中(例如SharedPreferences)。

爪哇

蜜蜂45

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.
    }
}

重新啟動過程併中斷上傳後,請再次調用putFile。但是這次也通過了被保存的Uri。

爪哇

//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

// 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)

會議持續一周。如果您在會話過期後嘗試恢復會話,或者遇到錯誤,則會收到失敗回調。您有責任確保兩次上傳之間文件均未更改。

錯誤處理

導致上載錯誤的原因有很多,其中包括本地文件不存在或用戶無權上載所需文件。您可以在文檔的“ 處理錯誤”部分中找到有關錯誤的更多信息。

完整的例子

帶有進度監控和錯誤處理的上傳的完整示例如下所示:

爪哇

// 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
        // ...
    }
});

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.ktx.component1 and 
// com.google.firebase.storage.ktx.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
    // ...
}

現在,您已經上傳了文件,讓我們學習如何從Cloud Storage 下載文件。