Xamarin Android中如何将图片保存到用户选择的目录
解决通过SAF选中目录保存Bitmap的问题
核心问题在于:SAF(存储访问框架)返回的Uri并非真实的本地文件系统路径,你不能直接通过File类或FileOutputStream访问这些Uri对应的文件,必须通过ContentResolver来操作文件流。
修正后的代码实现
替换你尝试的写文件代码,改用ContentResolver打开输出流直接写入Bitmap:
// 创建目标文件 DocumentFile docFile = documentFile.CreateFile("image/png", fileName); if (docFile == null) { Toast.MakeText(this, "无法创建目标文件", ToastLength.Short).Show(); return; } // 通过ContentResolver获取输出流,直接写入Bitmap try (OutputStream outputStream = ContentResolver.OpenOutputStream(docFile.Uri)) { // 直接压缩Bitmap到输出流,无需中转字节数组,更高效 imageBitmap.Compress(Bitmap.CompressFormat.Png, 100, outputStream); outputStream.Flush(); Toast.MakeText(this, "图片保存成功", ToastLength.Short).Show(); } catch (Java.IO.IOException e) { Android.App.AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.SetTitle("错误"); builder.SetMessage(e.Message); builder.SetNeutralButton("确定", (o, args) => {}); builder.Show(); }
错误原因说明
- SAF返回的Uri(如
content://com.android.providers.downloads.documents/tree/primary:Music/...)是系统文档提供器的抽象路径,并非磁盘上的真实文件路径。你之前获取的docFile.Uri.Path只是Uri的路径片段,不能直接用来创建File对象。 - Android 10及以上的分区存储机制,限制了应用直接访问外部存储的文件路径,必须通过SAF的内容提供器接口来操作文件。
完整修正后的SaveImage方法参考
private void SaveImage(Uri uri, string fileName) { var imageBitmap = Bitmap.CreateBitmap(pictureBox1.Width, pictureBox1.Height, Bitmap.Config.Argb8888); if (uri.Scheme.Equals("content")) { try { Context applicationContext = Application.Context; DocumentFile documentFile = DocumentFile.FromTreeUri(applicationContext, uri); if (documentFile != null && documentFile.Exists() && documentFile.IsDirectory) { // 创建目标文件 DocumentFile docFile = documentFile.CreateFile("image/png", fileName); if (docFile == null) { Toast.MakeText(this, "无法创建目标文件", ToastLength.Short).Show(); return; } // 写入Bitmap try (OutputStream outputStream = ContentResolver.OpenOutputStream(docFile.Uri)) { imageBitmap.Compress(Bitmap.CompressFormat.Png, 100, outputStream); outputStream.Flush(); Toast.MakeText(this, "图片保存成功", ToastLength.Short).Show(); } catch (Java.IO.IOException e) { Android.App.AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.SetTitle("错误"); builder.SetMessage(e.Message); builder.SetNeutralButton("确定", (o, args) => {}); builder.Show(); } } } catch (Exception ex) { Log.Debug("SaveImageError", ex.Message); Toast.MakeText(this, "保存失败:" + ex.Message, ToastLength.Long).Show(); } } }
内容的提问来源于stack exchange,提问作者user23633404
相关产品推荐
相关产品推荐

