【问题标题】:Json file not found after the Build构建后找不到 Json 文件
【发布时间】:2019-11-09 18:03:02
【问题描述】:

我想查找 json 文件的保存位置。在编辑器模式下我可以找到它。但是,当我制作游戏的构建时,我找不到它。

我正在使用这个脚本来保存游戏:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;

public class DataManager : MonoBehaviour
{
    public GameHandler data;
    private string file = "player.txt";

    public void Save()
    {
        string json = JsonUtility.ToJson(data);
        WriteTopFile(file, json);
    }

    public void Load()
    {
        data = new GameHandler();
        string json = ReadFromFile(file);
        JsonUtility.FromJsonOverwrite(json, data);
    }

    private void WriteTopFile(string fileName, string json)
    {
        string path = GetFilePath(fileName);
        FileStream fileStream = new FileStream(path, FileMode.Create);

        using (StreamWriter writer = new StreamWriter(fileStream))
        {
            writer.Write(json);
        } 
    }

    private string ReadFromFile(string fileName)
    {
        string path = GetFilePath(fileName);
        if (File.Exists(path))
        {
            print(path);
            using(StreamReader reader = new StreamReader(path))
            {
                string json = reader.ReadToEnd();
                return json;
            }
        }
        else
        {
            Debug.LogError("File not found");
            return "";
        }
    }

    private string GetFilePath(string fileName)
    {
        return Application.persistentDataPath + "/" + fileName;
    }
}

我怎样才能找到它呢?我可以指定它的路径吗?

【问题讨论】:

  • 我的直觉告诉我在 C:\Users\USER\AppData 的某个地方。
  • 但我希望它在构建文件夹中

标签: c# json visual-studio unity3d


【解决方案1】:

来自persistentDataPathafaik 的文件将不会自动打包到构建的应用程序中。

但是StreamingAssets是。

构建的应用可以在这个地址加载Asset。

所以我通常在编辑器中使用Application.streamingAssetsPath。这与简单地将文件放入文件夹Assets/StreamingAssets 相同。

我更喜欢这个,因为我不希望我的开发应用程序将一些文件膨胀到隐藏在 Windows PC 上的任何文件夹中,而是在相应项目的 Asset 文件夹中。

然后在构建后的运行时,此文件夹是只读的,并且在设备上不可见/不可访问。

所以我检查persistentDataPath 中是否存在相应的文件。

  • 如果是,请从那里读取 I。
  • 如果没有,那就从streamingAssetsPath 中读取一次,然后将其复制到persitentDataPath

另一个重点:

切勿将+"/"+ 用作文件路径

宁可使用Path.Combine,它会自动使用正确的平台特定路径分隔符!


代码取决于你的目标平台,因为

在 WebGL 和 Android 平台上无法访问 StreamingAssets 文件夹。 WebGL 上没有可用的文件访问权限。 Android 使用压缩的 .apk 文件。这些平台返回一个 URL。使用 UnityWebRequest 类访问资产。

我只会添加独立 (UWP) 的代码,因为我对 Android 没有太多经验,但使用 Coroutine 和 UnityWebRequest 阅读 streamingAssetsPath 应该是一样的

所以在代码中它可能类似于例如

#if UNITY_EDITOR
using UnityEditor;
#endif

...

private string DataFolder
{
#if UNITY_EDITOR
    return Application.streamingAssetsPath;
#else
    return Application.persitentDataPath;
#endif
}

private string GetFilePath(string fileName)
{
    return Path.Combine(DataFolder, fileName);
}

//                  | Little typo here btw
//                  v
private void WriteTopFile(string fileName, string json)
{
    string filePath = GetFilePath(fileName);

    // Create folder if not exists
    if(!Directory.Exists(DataFolder)
    {
        Directory.CreateDirectory(DataFolder);
    }

    using(var fileStream = new FileStream(filePath, FileMode.Create))
    {
        using (StreamWriter writer = new StreamWriter(fileStream))
        {
            writer.Write(json);
        }
    } 

#if UNITY_EDITOR
    AssetDataBase.Refresh();
#endif
}

现在在阅读如前所述时包括检查文件是否存在我是否存在持久路径:

private string ReadFromFile(string fileName)
{
    var filePath = GetFilePath(fileName);
    var output = "";

    Debug.Log($"Trying to read file {filePath}");
    if (File.Exists(filePath))
    {
        Debug.Log($"File found! Reading from {filePath}");
        using(StreamReader reader = new StreamReader(filePath))
        {
            output = reader.ReadToEnd();
        }
        return output;
    }

    // Otherwise rather try to read from streaming assets
    var altFilePath = Path.Combine(Application.streamingAssetsPath, fileName);
    Debug.LogWarning($"File not found! Instead trying to read file {altFilePath}");

    if(File.Exists(altFilePath)
    {
        // read from here but directly also write it back to persistentDataPath
        Debug.Log($"File found. Reading from {altFilePath}");

        // As mentioned for Android you would now do the rest in a Coroutine 
        // using a UnityWebRequest.Get              

        using(StreamReader reader = new StreamReader(altFilePath))
        {
            output = reader.ReadToEnd();
        }

        // Now before returning also write it to persistentDataPath
        WriteTopFile(fileName, output);
        return output;
    }

    // If this also fails you didn't put such a file to `Assets/StreamingAssets` before the build
    Debug.LogError($"File also not found in {altFilePath}/n/nRemember to play it in 'Assets/StreamingAssets' before building!");
    return output;
}

注意:目前我只是在打电话,所以没有保修,但我希望这个想法已经很清楚了 :)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-26
    • 2017-06-14
    • 2023-03-10
    • 2018-01-04
    • 2019-12-04
    • 2023-03-20
    • 2019-07-01
    相关资源
    最近更新 更多