Loading/saving xml files at runtime

After going through pretty much every forum and tutorial available I’m still unable to solve this.
I simply want to load and save xml data via runtime. It works in the editor, but not after build.
The paths are correct, I checked that (even after build).

Beside Application.streamingAssetsPath I’ve also tried dataPath and persistentDataPath. I’ve tried to put everything in the StreamingAssets folder that Unity copies and also in the C:/Users/User/DefaultCompany… path. It all works out perfectly fine before I build it…

Any suggestions?

    //Save the streamingDataObject to xml
    public void Save()
    {
        //Create new xml file
        XmlSerializer serializer = new XmlSerializer(typeof(ObjectDataBase));             //Create serializer
        FileStream stream = new FileStream(Application.streamingAssetsPath + "/XML/ObjectData", FileMode.Create); //Create file at this path
        serializer.Serialize(stream, oList);//Write the data in the xml file
        stream.Close();//Close the stream
    }

    //Load xml file
    public void Load()
    {
        XmlSerializer serializer = new XmlSerializer(typeof(ObjectDataBase));            //Create serializer
        FileStream stream = new FileStream(Application.streamingAssetsPath + "/XML/ObjectData", FileMode.Open); //Load file at this path
        oList = serializer.Deserialize(stream) as ObjectDataBase;
        stream.Close();//Close the stream
    }

This worked for me in both editor and after building:

       [Serializable]
       public struct Foo
       {
           public int x;
           public int y;

           public override string ToString() { return "x: " + x + ", y: " + y; }
       }

       string fileName = Application.streamingAssetsPath + "/XML/ObjectData.xml";

       public void Save()
       {
           var foo = new Foo()
           {
               x = 5,
               y = 10
           };

           XmlSerializer serializer = new XmlSerializer(typeof(Foo));

           using (FileStream stream = new FileStream(fileName, FileMode.Create))
           {
               serializer.Serialize(stream, foo);
           }
       }

       public void Load()
       {
           XmlSerializer serializer = new XmlSerializer(typeof(Foo));

           using (FileStream stream = new FileStream(fileName, FileMode.Open))
           {
               var foo = serializer.Deserialize(stream);

               Debug.Log(foo);
           }
       }

If you’re still having issues after building, then it’s likely you’re running into a permissions issue when trying to create an XML file in the build path. In my application’s installer, I set user-modify permissions on the data folder in order to allow me to create files there from within the application (it was actually for the output_log.txt log file that Unity generates, but you’ll likely need this for the XML file to be created).

I don’t think it’s an permission issue, since im the administrator. Also the StreamingAssets folder is build by Unity itself and it worked in editor mode. Maybe the DevelopmentBuild-log helps? I can read that something is wrong but not realy what it is. It told me not to use Application.streamingAssetsPath during serialisation, so I moved it to Start(). The warning is gone now, still doesn’t work, though.

Your code didn’t work either, throwing me an “InvalidOperationException: was not expected” exception. I’ll try moving around some lines.

Edit: I fixed the exception by adding

[Serializable, XmlRoot("StreamingData")]
    public struct Foo
    {...}

Edit #2:
Still, xml isn’t loaded (I guess, stupid as I am I simply output the data directly instead of loading my xml).

Weirdly enough, that doesn’t seem to matter if you’re building for Windows standalone. I’m not sure what platform you’re targeting, but in my case, I still had to set the user-modify permission even though I’m the administrator as well. However, this seems to only be true if I install to C:\Program FIles. If the build is anywhere else, then it works fine.

Your case may be different if you’re targeting a different platform though.

Are you getting any errors at all in the console output? Or does it just silently fail when trying to create the xml data?

No errors. It just fails. With your example “foo” contains the xml data, but I have no idea how to get the x and y values now. Also I need a list of objects, which contain a lot of data.

The struct is just a test case for trying to make sure serialization/deserialization works. It’s best to stick with something simple for now until you can be sure the file creation/serialization part works, then you can switch to a list afterwards.

Maybe you should first focus on trying to create the XML file in that path, and figure out why you’re not able to. Try using File.Create() (or File.CreateText()) in that path, and see if you get any errors or exceptions thrown. Hopefully that’ll give you more info to work with.

Im getting this error now, using development build to get a log file. And yes, yes I’m building for windows.

IOException: Sharing violation on path This should happen, if you try to read/write at the same time. It can usually be fixed by closing the stream, which I already do. So this is strange. Also this only appears if I hit the “Save” button in my application, to call Save(). Load() is called at Start().

Full Log File

Mono path[0] = ‘C:/Users/Fuby/Desktop/ThrowsInVr_Data/Managed’
Mono path[1] = ‘C:/Users/Fuby/Desktop/ThrowsInVr_Data/Mono’
Mono config path = ‘C:/Users/Fuby/Desktop/ThrowsInVr_Data/Mono/etc’
PlayerConnection initialized from C:/Users/Fuby/Desktop/ThrowsInVr_Data (debug = 0)
PlayerConnection initialized network socket : 0.0.0.0 55249
Multi-casting “[IP] 192.168.2.102 [Port] 55249 [Flags] 2 [Guid] 1043403477 [EditorId] 512348568 [Version] 1048832 [Id] WindowsPlayer(Fuby-PC) [Debug] 0” to [225.0.0.222:54997]…
Started listening to [0.0.0.0:55249]
PlayerConnection already initialized - listening to [0.0.0.0:55249]
Player data archive not found at C:/Users/Fuby/Desktop/ThrowsInVr_Data/data.unity3d, using local filesystemInitialize engine version: 5.6.0f3 (497a0f351392)
GfxDevice: creating device client; threaded=1
Direct3D:
Version: Direct3D 11.0 [level 11.0]
Renderer: AMD Radeon HD 7700 Series (ID=0x683d)
Vendor: ATI
VRAM: 1003 MB
Driver: 14.502.1002.0
Begin MonoManager ReloadAssembly
Platform assembly: C:\Users\Fuby\Desktop\ThrowsInVr_Data\Managed\UnityEngine.dll (this message is harmless)
Loading C:\Users\Fuby\Desktop\ThrowsInVr_Data\Managed\UnityEngine.dll into Unity Child Domain
Platform assembly: C:\Users\Fuby\Desktop\ThrowsInVr_Data\Managed\Assembly-CSharp.dll (this message is harmless)
Loading C:\Users\Fuby\Desktop\ThrowsInVr_Data\Managed\Assembly-CSharp.dll into Unity Child Domain
Platform assembly: C:\Users\Fuby\Desktop\ThrowsInVr_Data\Managed\UnityEngine.UI.dll (this message is harmless)
Loading C:\Users\Fuby\Desktop\ThrowsInVr_Data\Managed\UnityEngine.UI.dll into Unity Child Domain
Platform assembly: C:\Users\Fuby\Desktop\ThrowsInVr_Data\Managed\UnityEngine.Networking.dll (this message is harmless)
Loading C:\Users\Fuby\Desktop\ThrowsInVr_Data\Managed\UnityEngine.Networking.dll into Unity Child Domain
Platform assembly: C:\Users\Fuby\Desktop\ThrowsInVr_Data\Managed\UnityEngine.VR.dll (this message is harmless)
Loading C:\Users\Fuby\Desktop\ThrowsInVr_Data\Managed\UnityEngine.VR.dll into Unity Child Domain
Platform assembly: C:\Users\Fuby\Desktop\ThrowsInVr_Data\Managed\LeapCSharp.NET3.5.dll (this message is harmless)
Loading C:\Users\Fuby\Desktop\ThrowsInVr_Data\Managed\LeapCSharp.NET3.5.dll into Unity Child Domain

  • Completed reload, in 0.203 seconds
    Platform assembly: C:\Users\Fuby\Desktop\ThrowsInVr_Data\Managed\System.Core.dll (this message is harmless)
    Platform assembly: C:\Users\Fuby\Desktop\ThrowsInVr_Data\Managed\System.dll (this message is harmless)
    OnLevelWasLoaded was found on OVRScreenFade
    This message has been deprecated and will be removed in a later version of Unity.
    Add a delegate to SceneManager.sceneLoaded instead to get notifications after scene loading has completed
    (Filename: C:\buildslave\unity\build\Runtime/Mono/MonoScriptCache.cpp Line: 376)

desktop: 1600x900 60Hz; virtual: 1600x900 at 0,0
Initializing input.

Input initialized.

Initialized touch support.

UnloadTime: 2.242631 ms
Platform assembly: C:\Users\Fuby\Desktop\ThrowsInVr_Data\Managed\System.Xml.dll (this message is harmless)
ArgumentException: Encoding name ‘Windows-1252’ not supported
Parameter name: name
at System.Text.Encoding.GetEncoding (System.String name) [0x000ed] in /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Text/Encoding.cs:718
at System.Xml.XmlInputStream.Initialize (System.IO.Stream stream) [0x00265] in /Users/builduser/buildslave/mono/build/mcs/class/System.XML/System.Xml/XmlInputStream.cs:459
at System.Xml.XmlInputStream…ctor (System.IO.Stream stream) [0x00006] in /Users/builduser/buildslave/mono/build/mcs/class/System.XML/System.Xml/XmlInputStream.cs:359
at System.Xml.XmlStreamReader…ctor (System.IO.Stream input) [0x00000] in :0
at System.Xml.XmlTextReader…ctor (System.IO.Stream input) [0x00000] in :0
at System.Xml.Serialization.XmlSerializer.Deserialize (System.IO.Stream stream) [0x00000] in /Users/builduser/buildslave/mono/build/mcs/class/System.XML/System.Xml.Serialization/XmlSerializer.cs:327
at XMLManager.Load () [0x00021] in C:\Users\Fuby\Desktop\Patrick\ThrowsInVR\Assets\1. Master Thesis\Scripts\Menue\XMLManager.cs:85
at XMLManager.Start () [0x00018] in C:\Users\Fuby\Desktop\Patrick\ThrowsInVR\Assets\1. Master Thesis\Scripts\Menue\XMLManager.cs:31
(Filename: /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Text/Encoding.cs Line: 718)

ArgumentException: Encoding name ‘Windows-1252’ not supported
Parameter name: name
at System.Text.Encoding.GetEncoding (System.String name) [0x000ed] in /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Text/Encoding.cs:718
at System.Xml.XmlInputStream.Initialize (System.IO.Stream stream) [0x00265] in /Users/builduser/buildslave/mono/build/mcs/class/System.XML/System.Xml/XmlInputStream.cs:459
at System.Xml.XmlInputStream…ctor (System.IO.Stream stream) [0x00006] in /Users/builduser/buildslave/mono/build/mcs/class/System.XML/System.Xml/XmlInputStream.cs:359
at System.Xml.XmlStreamReader…ctor (System.IO.Stream input) [0x00000] in :0
at System.Xml.XmlTextReader…ctor (System.IO.Stream input) [0x00000] in :0
at System.Xml.Serialization.XmlSerializer.Deserialize (System.IO.Stream stream) [0x00000] in /Users/builduser/buildslave/mono/build/mcs/class/System.XML/System.Xml.Serialization/XmlSerializer.cs:327
at ObjectManager.Load () [0x00021] in C:\Users\Fuby\Desktop\Patrick\ThrowsInVR\Assets\1. Master Thesis\Scripts\Objects\ObjectManager.cs:80
at ObjectManager.Start () [0x0002c] in C:\Users\Fuby\Desktop\Patrick\ThrowsInVR\Assets\1. Master Thesis\Scripts\Objects\ObjectManager.cs:38
(Filename: /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Text/Encoding.cs Line: 718)

Setting up 2 worker threads for Enlighten.
Thread → id: 21e8 → priority: 1
Thread → id: 1550 → priority: 1
IOException: Sharing violation on path C:\Users\Fuby\Desktop\ThrowsInVr_Data\StreamingAssets\XML\StreamingData
at System.IO.FileStream…ctor (System.String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, Boolean anonymous, FileOptions options) [0x00370] in /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.IO/FileStream.cs:354
at System.IO.FileStream…ctor (System.String path, FileMode mode) [0x00000] in :0
at XMLManager.Save () [0x00018] in C:\Users\Fuby\Desktop\Patrick\ThrowsInVR\Assets\1. Master Thesis\Scripts\Menue\XMLManager.cs:75
at XMLManager.SaveStreamingData () [0x000ea] in C:\Users\Fuby\Desktop\Patrick\ThrowsInVR\Assets\1. Master Thesis\Scripts\Menue\XMLManager.cs:67
at UnityEngine.Events.InvokableCall.Invoke (System.Object[ ] args) [0x00017] in C:\buildslave\unity\build\Runtime\Export\UnityEvent.cs:154
at UnityEngine.Events.InvokableCallList.Invoke (System.Object[ ] parameters) [0x00056] in C:\buildslave\unity\build\Runtime\Export\UnityEvent.cs:637
at UnityEngine.Events.UnityEventBase.Invoke (System.Object[ ] parameters) [0x0000e] in C:\buildslave\unity\build\Runtime\Export\UnityEvent.cs:773
at UnityEngine.Events.UnityEvent.Invoke () [0x00008] in C:\buildslave\unity\build\Runtime\Export\UnityEvent_0.cs:52
at UnityEngine.UI.Button.Press () [0x0001c] in C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\UI\Core\Button.cs:35
at UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) [0x00012] in C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\UI\Core\Button.cs:44
at UnityEngine.EventSystems.ExecuteEvents.Execute (IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) [0x00008] in C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\ExecuteEvents.cs:50
at UnityEngine.EventSystems.ExecuteEvents.Execute[IPointerClickHandler] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.EventFunction1 functor) [0x00073] in C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\ExecuteEvents.cs:261 UnityEngine.DebugLogHandler:Internal_LogException(Exception, Object) UnityEngine.DebugLogHandler:LogException(Exception, Object) UnityEngine.Logger:LogException(Exception, Object) UnityEngine.Debug:LogException(Exception) UnityEngine.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction1) (at C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\ExecuteEvents.cs:265)
UnityEngine.EventSystems.StandaloneInputModule:ProcessMousePress(MouseButtonEventData) (at C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\InputModules\StandaloneInputModule.cs:533)
UnityEngine.EventSystems.StandaloneInputModule:ProcessMouseEvent(Int32) (at C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\InputModules\StandaloneInputModule.cs:432)
UnityEngine.EventSystems.StandaloneInputModule:ProcessMouseEvent() (at C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\InputModules\StandaloneInputModule.cs:412)
UnityEngine.EventSystems.StandaloneInputModule:Process() (at C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\InputModules\StandaloneInputModule.cs:186)
UnityEngine.EventSystems.EventSystem:Update() (at C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\EventSystem.cs:283)
(Filename: /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.IO/FileStream.cs Line: 354)

I figured it out (after 12h straight).
Seems like I need to overwrite existing xml files in my build by saving them at runtime. Then I can restart it and it will load… the copied xml files, I saved while in editor mode won’t be loaded (even though they are copied into StreamingAssets and you can open and change them in the editor). Also you can’t just move xml files into your StreamingAssets folder. They have to be generatet during runtime. Ofcourse I’ve tried that before, but without setting the root element. [Serializable, XmlRoot(“StreamingData”)]
At least that seems to work.

Thanks for your effort.

Full working code:

public class ObjectManager : MonoBehaviour
{
    //Singleton
    public static ObjectManager oManager;

    void Awake()
    {
        oManager = this;
    }

    void Start()
    {
        path = Application.streamingAssetsPath + "/XML/ObjectData";
        Load();//Load xml file and save it into oList
    }

    //Save the streamingDataObject to xml
    public void Save()
    {
        //Create new xml file
        XmlSerializer serializer = new XmlSerializer(typeof(ObjectDataBase)); //Create serializer
        FileStream stream = new FileStream(path, FileMode.Create); //Create file at this path
        serializer.Serialize(stream, oList);//Write the data in the xml file
        stream.Close();//Close the stream
    }

    //Load xml file
    public void Load()
    {
        XmlSerializer serializer = new XmlSerializer(typeof(ObjectDataBase)); //Create serializer
        FileStream stream = new FileStream(path, FileMode.Open); //Load file at this path
        oList = serializer.Deserialize(stream) as ObjectDataBase;
        stream.Close();//Close the stream
    }
}

////////////////////////  XML - Serializable  ////////////////////
[Serializable, XmlRoot("StreamingData")]
public class BasicObject
{
    //Stats
    public string objectName; //Reference name for DropDown
    public string objectType; //Type of the object
    public int objectID; //Reference name for Motive
    public string modelPath; //You can only import .obj files at the moment

    //Constructor
    public BasicObject()
    {
        objectName = "Object: " + Math.Round(Time.time, 1, MidpointRounding.AwayFromZero); //Unique, chronologically ordered name
        objectType = ""; //Standard should be empty?
        objectID = -1; //-1 so it won`t accidently receive data from Motive
        modelPath = ""; //Standard should be empty?
    }
}

[Serializable, XmlRoot("StreamingData")]
public class ObjectDataBase
{
    public List<BasicObject> list = new List<BasicObject>();
}
}

It appears your Load() function is actually throwing an exception: ArgumentException: Encoding name 'Windows-1252' not supported

Have you switched to using statements? If not, then the exception may have been thrown before the stream.Close() statement is reached.

1 Like

I happen to have made a thread asking in a lot of detail about this subject and a user called HiddenMonk wrote some very detailed information on serialising gameobjects, it should help you a huge amount in the future if you run into problems dealing with XML in particular.

It is not a subject that programmers have done a lot of documentation about unfortunately as you can see in the thread I initially had to pick a fight with people in order to get a straight answer. Part of it seems to be just lack of interest in generally teaching or talking about the subject but another is you have to be very specific about what you want since you have multiple methods for various game genres and what type of data you’re saving.

1 Like