user11660804
user11660804

Reputation:

Json file not found after the Build

I'd like to find where the json file is saved. In the editor mode I can find it. However, when I make the build of the game, I cannot find it.

I'm using this script to save the game:

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;
    }
}

How can I find it guys? Can I specify its the path?

Upvotes: 0

Views: 3360

Answers (1)

derHugo
derHugo

Reputation: 90833

Files from persistentDataPath afaik will not be packed automatically into the built application.

But the StreamingAssets are.

The built application can load the Asset at this address.

So what I usually do is using the Application.streamingAssetsPath while still being in the Editor. This is the same as simply putting a file into the folder Assets/StreamingAssets.

I prefer this I general since I don't want my development application bloating some files into any folder hidden on the Windows PC but instead within the according project's Asset folder.

Then on runtime after a build this folder is read-only and not visible/accessible on the device.

So I check if the according file exists in the persistentDataPath.

  • If yes read I from there.
  • If not then rather read it once from the streamingAssetsPath and copy it into the persitentDataPath.

Another important point:

Do never use +"/"+ for file paths

rather use Path.Combine which uses automatically the correct platform specific path separator symbol!


The code depends a bit which is your target platform since the

It is not possible to access the StreamingAssets folder on WebGL and Android platforms. No file access is available on WebGL. Android uses a compressed .apk file. These platforms return a URL. Use the UnityWebRequest class to access the Assets.

I will only add the code for standalone (UWP) because I have not much experience with Android but it should be the same just using a Coroutine and UnityWebRequest for reading the streamingAssetsPath

So in code it could be something like e.g.

#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
}

Now when reading as said before include a check if file exists I persistent path or not:

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;
}

Note: Currently I'm only on the phone so no warranty but I hope the idea gets clear already :)

Upvotes: 1

Related Questions