Search Unity

Loading files from Resources vs from external folder

Discussion in 'Scripting' started by vicentcamison, May 10, 2020.

  1. vicentcamison

    vicentcamison

    Joined:
    Oct 5, 2018
    Posts:
    2
    Hey guys,
    I'm stuck with this problem for more than a day, and I still haven't been able to find where I went wrong.

    I'm trying to save and load levels for my game. I'm going to load the levels from two different places: from user files for levels created by users using an ingame level editor, and from the resources folder for the game's normal levels.
    (In the code, this is referred as the 'from' variable: from=0 means using the Resources folder, and from=1 means using Application.persistentDataPath.

    Currently, I'm able to load the level perfectly from files outside the game (from = 1), but I run into many errors when loading the file from the Resources folder. I should also say that, when previewing the file in the Unity Editor, it appears to be empty. However, it is not empty, as it does contain byte info.
    The error I'm currently running at when trying to load the file from the Resources folder is ArgumentException: Name has invalid chars.

    Here you can see the code I'm using to load the files:

    Code (CSharp):
    1. switch (from)
    2.         {
    3.             //the level comes from ADVENTURE files
    4.             case 0:
    5.                 TextAsset data = Resources.Load<TextAsset>("Levels/Adventure/" + levelNumber.ToString());
    6.                 string txt = data.text;
    7.                 if (txt == "")
    8.                     txt = System.Text.Encoding.Default.GetString(data.bytes);
    9.                 if (txt != null)
    10.                 {
    11.                     Debug.Log(txt);
    12.                     BinaryFormatter formatter = new BinaryFormatter();
    13.                     FileStream stream = new FileStream(txt, FileMode.Open);
    14.  
    15.                     ld = formatter.Deserialize(stream) as LevelData;
    16.                     Debug.Log(ld.levelMechanics[2].name);
    17.  
    18.                     stream.Close();
    19.                 }
    20.                 break;
    21.  
    22.             // the level comes from USER files
    23.             case 1:
    24.                 string path = Application.persistentDataPath + "/" + levelNumber.ToString() + ".mg2";
    25.                 if (File.Exists(path))
    26.                 {
    27.                     Debug.Log("File found!");
    28.                     BinaryFormatter formatter = new BinaryFormatter();
    29.                     FileStream stream = new FileStream(path, FileMode.Open);
    30.  
    31.                     ld = formatter.Deserialize(stream) as LevelData;
    32.                     Debug.Log(ld.levelMechanics[2].name);
    33.  
    34.                     stream.Close();
    35.                 }
    36.                 break;
    37.  
    38.         }        
    What am I doing wrong? If, for whatever reason what I'm trying to achieve is not possible, is there any workaround to achieve this?
    Thanks for your time.
     
  2. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Well... log the path and check what it is. The path you pass in has invalid chars.

    Also, post the complete error. I guess the exception doesn't occur when you try to read the text asset, but when you attempt to initialize the FileStream with path = txt, which doesn't make a whole lot of sense unless you saved just another path there.If you did, continue with what I mentioned before. Log it, and try to figure out what's wrong. Perhaps there's a ling ending or something that is not supported by the file system.

    Also note that Resources will not be available as a normal folder in the final build. It'll be packed into file that you can only access using the Resources API. That matters if your code was supposed to read something with a normal stream from the source location.
    Secondary note to Resources, you should try to minimize the content that's placed there. AssetBundles and Adressables are the better choice.

    Last but not least, use the using-block for disposable types such as streams rather than disposing/closing streams manually, unless you need them to stay open much longer / need explicit control. Your code may leave the stream object opened in case of an exceptional case, so that it won't free the resources until the object is finalized by the GC.
     
  3. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    you could copy your whole code from case 1 but replace the 1st line to
    Code (CSharp):
    1.    string path = Application.dataPath + "/Resources/" + levelNumber.ToString() + ".mg2";
    2.              
     
  4. vicentcamison

    vicentcamison

    Joined:
    Oct 5, 2018
    Posts:
    2
    Thanks for the many tips Suddoha. I'm a noob at programming so this kind of additional information is always appreciated. I will definitely take a look at everything you proposed. I'm currently away from the computer, so I cannot test the answer right now.

    Brigas, you're right. Thanks for letting me know.
     
  5. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    no problem, also I'm not sure about this I think your error in the first place happens because your path is being returned with " \ " left slashes which are invalid and you need to replace in the string with " / " slashes