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

Xamarin.Android复制Assets内容到内部存储时Open文件报错解决

Xamarin.Android Assets文件复制异常问题排查与解决

我需要将Xamarin.Android项目中Assets目录下html/Model1/Content文件夹内的10余个文件,复制到应用数据文件夹下新建的Models文件夹中,编写了如下异步复制代码,但运行时在assetManager.Open(filename)处触发异常,第一个文件0.pf就出现该问题:

private async Task copyFileAsync()
{
  
    var outputName = Application.Context.GetExternalFilesDir("").AbsolutePath + "/Models";
    if (!System.IO.File.Exists (outputName))
    {
        Directory.CreateDirectory(outputName);
    }
    AssetManager assetManager = this.Assets;
    String[] files = null;
    try
    {
        files = assetManager.List("html/Model1/Content");
    }
    catch (System.IO.IOException e)
    {
        System.Console.WriteLine("tag", "Failed to get asset file list.", e);
    }
    foreach (String filename in files)
    {
       
        string filePath = System.IO.Path.Combine(outputName, filename);
        using (var fileAssetStream = assetManager.Open(filename))
        using (var fileStream = new FileStream (filePath, FileMode.OpenOrCreate))
        {
            await copyInToLocationAsync(fileAssetStream, fileStream, filePath);
        }
        
       System.Console.WriteLine("------COPIED------------------------");
        
    }

   
}

private async Task copyInToLocationAsync(Stream fileAssetStream, Stream fileStream, string path)
{
    byte[] buffer = new byte[1024];
    int b = buffer.Length;
    int length;
        while ((length = await fileAssetStream.ReadAsync(buffer, 0, b)) > 0)
        {
            await fileStream.WriteAsync(buffer, 0, length);
        }

        fileStream.Flush();
        fileStream.Close();
        fileAssetStream.Close();
}

异常原因分析

  • Asset路径错误:assetManager.List("html/Model1/Content")获取到的是该子目录下的纯文件名,但assetManager.Open(filename)时没有带上完整相对路径,AssetManager会默认在Assets根目录查找文件,自然找不到目标文件,抛出不存在异常。
  • 目录判断逻辑错误:用File.Exists(outputName)判断目录是否存在,这是用来检测文件的方法,应该用Directory.Exists,否则目录已存在时会执行无效的创建操作。
  • 冗余流操作:copyInToLocationAsync中手动调用Close(),但外层using语句会自动释放流资源,手动关闭属于冗余操作。

解决方法与修正代码

  1. 修正Asset文件路径:打开文件时使用完整相对路径,通过Path.Combine拼接目录和文件名。
  2. 修复目录存在判断:替换File.Exists为Directory.Exists。
  3. 移除冗余流关闭代码:依赖using自动管理流资源。

修正后的完整代码:

private async Task CopyFileAsync()
{
    // 用Path.Combine拼接路径,避免字符串拼接的潜在问题
    var outputDir = Path.Combine(Application.Context.GetExternalFilesDir("").AbsolutePath, "Models");
    if (!Directory.Exists(outputDir))
    {
        Directory.CreateDirectory(outputDir);
    }

    AssetManager assetManager = this.Assets;
    string[] files = null;
    try
    {
        files = assetManager.List("html/Model1/Content");
    }
    catch (IOException e)
    {
        Console.WriteLine("获取Asset文件列表失败:", e);
    }

    // 空值判断,避免空数组遍历
    if (files == null || files.Length == 0)
        return;

    foreach (string filename in files)
    {
        string filePath = Path.Combine(outputDir, filename);
        // 使用完整的Asset相对路径打开文件
        using (var fileAssetStream = assetManager.Open(Path.Combine("html/Model1/Content", filename)))
        using (var fileStream = new FileStream(filePath, FileMode.OpenOrCreate))
        {
            await CopyIntoLocationAsync(fileAssetStream, fileStream);
        }
        Console.WriteLine($"已复制文件:{filename}");
    }
}

private async Task CopyIntoLocationAsync(Stream fileAssetStream, Stream fileStream)
{
    byte[] buffer = new byte[1024];
    int length;
    while ((length = await fileAssetStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
    {
        await fileStream.WriteAsync(buffer, 0, length);
    }
    // using块会自动处理流的Flush和释放,无需手动操作
}

内容的提问来源于stack exchange,提问作者Randi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 17:54:57