Android中FileProvider获取的图片Uri无法上传至AWS S3
The core issue here is that FileProvider returns a content URI (content://), not a direct file system path. When you try to create a File object using imgUri.getPath(), it doesn't point to an actual file on the device's filesystem—this is exactly why you're seeing the "Invalid file" exception from AWS TransferUtility.
Here are two reliable solutions to fix this:
Solution 1: Upload Using InputStream (Recommended)
This approach reads the image content directly from the content URI via an InputStream and passes it to TransferUtility, avoiding unnecessary temporary file creation.
Step-by-Step Code Implementation:
- Get an InputStream from the content URI using
ContentResolver:
InputStream inputStream = null; try { inputStream = getContext().getContentResolver().openInputStream(imgUri); } catch (FileNotFoundException e) { e.printStackTrace(); // Handle error: Failed to access the image file }
- Create ObjectMetadata to specify key file details (optional but improves upload reliability):
ObjectMetadata metadata = new ObjectMetadata(); metadata.setContentType("image/jpeg"); // Adjust based on your image type (e.g., image/png) // Optional: Set the file size if you can retrieve it Cursor cursor = getContext().getContentResolver().query(imgUri, null, null, null, null); if (cursor != null) { int sizeColumnIndex = cursor.getColumnIndex(OpenableColumns.SIZE); cursor.moveToFirst(); metadata.setContentLength(cursor.getLong(sizeColumnIndex)); cursor.close(); }
- Upload using the InputStream overload of TransferUtility:
if (inputStream != null) { TransferObserver transferObserver = transferUtility.upload( "my_bucket", bucketFilePath, inputStream, metadata, CannedAccessControlList.PublicRead ); // Add a TransferListener to track upload progress/status if needed }
Solution 2: Copy to Temporary File and Upload
If you prefer working with a File object, copy the content from the content URI to a temporary file in your app's private cache directory, then upload that file.
Code Example:
// Create a temporary file in the app's cache directory File tempUploadFile = new File(getContext().getCacheDir(), "temp_s3_upload.jpg"); // Copy content from the content URI to the temp file try (InputStream in = getContext().getContentResolver().openInputStream(imgUri); OutputStream out = new FileOutputStream(tempUploadFile)) { byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesRead); } } catch (IOException e) { e.printStackTrace(); // Handle error: Failed to copy the file } // Upload the temporary file to S3 TransferObserver transferObserver = transferUtility.upload( "my_bucket", bucketFilePath, tempUploadFile, CannedAccessControlList.PublicRead ); // Optional: Clean up the temp file after upload finishes transferObserver.setTransferListener(new TransferListener() { @Override public void onStateChanged(int id, TransferState state) { if (state == TransferState.COMPLETED || state == TransferState.FAILED) { tempUploadFile.delete(); } } @Override public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {} @Override public void onError(int id, Exception ex) {} });
Key Notes:
- Always handle exceptions (like
FileNotFoundExceptionorIOException) to prevent app crashes. - For Solution 1, TransferUtility will handle closing the
InputStreamonce the upload completes, but double-check your implementation if you're adding custom listeners. - For Solution 2, using
getCacheDir()ensures the temporary file is private to your app and will be cleared automatically if the app is uninstalled—no extra storage permissions required.
内容的提问来源于stack exchange,提问作者Mazid

