You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 19:52:57