Xamarin Android 11及以上:将内部存储JPG文件复制至文档/下载目录
Xamarin Android 11+ 复制应用内部JPG到公共目录示例代码
权限配置
在AndroidManifest.xml中添加兼容不同版本的必要权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="30" /> <!-- Android 10及以下需写入权限,11+通过MediaStore API无需此权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
核心复制代码
直接嵌入应用即可使用,包含遍历内部存储JPG、复制到公共Downloads/Documents目录的完整逻辑:
using System.IO; using System.Linq; using Android.Content; using Android.OS; using Android.Provider; using Android.Widget; public class FileCopyHelper { /// <summary> /// 复制应用内部存储的所有JPG文件到公共Downloads目录 /// </summary> public async Task CopyAllJpgToPublicDownloads() { var internalFilesDir = Application.Context.FilesDir; // 遍历内部存储下所有.jpg/.JPG文件 var jpgFiles = internalFilesDir.ListFiles(f => f.Name.EndsWith(".jpg", System.StringComparison.OrdinalIgnoreCase)); if (jpgFiles == null || !jpgFiles.Any()) { Toast.MakeText(Application.Context, "未找到JPG文件", ToastLength.Short).Show(); return; } foreach (var file in jpgFiles) { await CopySingleJpgToPublicDir(file, Environment.DirectoryDownloads); } Toast.MakeText(Application.Context, "JPG文件复制完成", ToastLength.Short).Show(); } /// <summary> /// 复制单个JPG文件到指定公共目录(Downloads/Documents) /// </summary> /// <param name="sourceFile">源文件(应用内部存储的JPG)</param> /// <param name="targetPublicDir">目标公共目录,如Environment.DirectoryDownloads或Environment.DirectoryDocuments(仅API30+支持)</param> private async Task CopySingleJpgToPublicDir(File sourceFile, string targetPublicDir) { var resolver = Application.Context.ContentResolver; var contentValues = new ContentValues(); // 设置文件元数据 contentValues.Put(MediaStore.Images.Media.Columns.DisplayName, sourceFile.Name); contentValues.Put(MediaStore.Images.Media.Columns.MimeType, "image/jpeg"); contentValues.Put(MediaStore.Images.Media.Columns.RelativePath, targetPublicDir); // 插入文件记录到MediaStore,获取目标URI var targetUri = resolver.Insert(MediaStore.Images.Media.ExternalContentUri, contentValues); if (targetUri == null) { Toast.MakeText(Application.Context, $"创建文件{sourceFile.Name}失败", ToastLength.Short).Show(); return; } try { // 打开流并复制文件内容 using var inputStream = new FileStream(sourceFile.Path, FileMode.Open, FileAccess.Read); using var outputStream = resolver.OpenOutputStream(targetUri); await inputStream.CopyToAsync(outputStream); } catch (IOException ex) { Toast.MakeText(Application.Context, $"复制{sourceFile.Name}失败: {ex.Message}", ToastLength.Short).Show(); // 删除创建的空文件 resolver.Delete(targetUri, null, null); } } /// <summary> /// 复制应用内部存储的所有JPG文件到公共Documents目录(仅Android 11+支持) /// </summary> public async Task CopyAllJpgToPublicDocuments() { if (Build.VERSION.SdkInt < BuildVersionCodes.R) { Toast.MakeText(Application.Context, "Documents目录仅支持Android 11及以上版本", ToastLength.Short).Show(); return; } var internalFilesDir = Application.Context.FilesDir; var jpgFiles = internalFilesDir.ListFiles(f => f.Name.EndsWith(".jpg", System.StringComparison.OrdinalIgnoreCase)); if (jpgFiles == null || !jpgFiles.Any()) { Toast.MakeText(Application.Context, "未找到JPG文件", ToastLength.Short).Show(); return; } foreach (var file in jpgFiles) { await CopySingleJpgToPublicDir(file, Environment.DirectoryDocuments); } Toast.MakeText(Application.Context, "JPG文件复制完成", ToastLength.Short).Show(); } }
使用方式
在Activity或Fragment中通过按钮点击等事件触发:
private async void btnCopyToDownloads_Click(object sender, EventArgs e) { var copyHelper = new FileCopyHelper(); await copyHelper.CopyAllJpgToPublicDownloads(); } private async void btnCopyToDocuments_Click(object sender, EventArgs e) { var copyHelper = new FileCopyHelper(); await copyHelper.CopyAllJpgToPublicDocuments(); }
注意事项
- Android 11+ 无需申请
WRITE_EXTERNAL_STORAGE权限,通过MediaStore API即可写入公共目录 Documents目录仅在Android 11(API 30)及以上版本可用,低版本需改用Downloads目录- 复制过程中需处理IO异常,避免因文件占用、存储空间不足等问题导致应用崩溃
- 应用内部存储的文件为私有资源,读取无需额外权限
内容的提问来源于stack exchange,提问作者DeonJoubert
相关产品推荐
相关产品推荐

