简体   繁体   中英

Reading XML files in a Unity HoloLens project : works in Editor, not in deployed project

I'm trying to save and load a custom class 'Animation' (A list of quaternions, an int for an ID and an int to indicate how many game objects there are to animate), and the saving part works just fine on HoloLens, but the loading part only works on PC for some reason. On HoloLens, it returns the error: "There is an error in XML document (2, 2)."

I've tried using StreamingAssets instead of 'persistentDataPath' for my files, but once again, on HoloLens, I get an error that explains that the access to the file was denied.

I've also tried loading the 'Animation' using a TextReader and a StreamReader, but the results are the exact same.

I've also tried writing the 'Animation' using a StreamWriter, but the results did not change either.

I've joined the code of the class that is in charge of writing and loading the XML files, as well as an example of what the 'SaveAnimation' function writes with success every time.

Any ideas what the problem could be? I'm pretty sure the issue is with how I write the XML file, but I can't seem to find a solution.

The code for the Save/Load class:

using System.IO;
using System.Xml.Serialization;
using UnityEngine;

public class AnimationSaverLoader : MonoBehaviour {

    private string baseFilename = "animation";

    private string path;

    public bool SaveAnimation(Animation animation)
    {
        int animationID = animation.AnimationID;
        path = Path.GetFullPath(Path.Combine(Application.persistentDataPath, baseFilename + animationID + ".xml"));

        try
        {
            using (FileStream writer = new FileStream(path, FileMode.Create))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(Animation));
                serializer.Serialize(writer, animation);
            }
            return true;
        }
        catch (System.Exception e)
        {
            Debug.LogWarning("Error saving animation : " + e.Message);
            return false;
        }
    }

    public Animation LoadAnimation(int animationID)
    {
        path = Path.GetFullPath(Path.Combine(Application.persistentDataPath, baseFilename + animationID + ".xml"));
        Animation deserialized = null;

        try
        {
            using (FileStream reader = File.Open(path, FileMode.Open))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(Animation));
                deserialized = (Animation)serializer.Deserialize(reader);
            }
        }
        catch (System.Exception e)
        {
            Debug.LogWarningFormat("Error loading animation : {0}", e.Message);
        }

        Debug.LogFormat("deserialized is null : {0}", deserialized == null);

        return deserialized;
    }

And an example of the XML output of the 'SaveAnimation' function:

<?xml version="1.0" encoding="utf-8"?>
<Animation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <nbAnimatables>7</nbAnimatables>
  <animationID>1</animationID>
  <points>
    <ArrayOfQuaternion>
      <Quaternion>
        <x>0</x>
        <y>0</y>
        <z>0</z>
        <w>1</w>
        <eulerAngles>
          <x>-0</x>
          <y>0</y>
          <z>0</z>
        </eulerAngles>
      </Quaternion>
      <Quaternion>
        <x>0</x>
        <y>0</y>
        <z>0</z>
        <w>1</w>
        <eulerAngles>
          <x>-0</x>
          <y>0</y>
          <z>0</z>
        </eulerAngles>
      </Quaternion>
      <Quaternion>
        <x>-0</x>
        <y>-0</y>
        <z>-0</z>
        <w>1</w>
        <eulerAngles>
          <x>-0</x>
          <y>0</y>
          <z>0</z>
        </eulerAngles>
      </Quaternion>
      <Quaternion>
        <x>-0.229409814</x>
        <y>0.0272422452</y>
        <z>-0.114730783</z>
        <w>0.966160357</w>
        <eulerAngles>
          <x>334.0847</x>
          <y>6.722004</y>
          <z>344.9074</z>
        </eulerAngles>
      </Quaternion>
      <Quaternion>
        <x>-0.0120867919</x>
        <y>0.009940858</y>
        <z>-0.0253626034</z>
        <w>0.9995558</w>
        <eulerAngles>
          <x>358.644348</x>
          <y>1.17417169</y>
          <z>357.0791</z>
        </eulerAngles>
      </Quaternion>
      <Quaternion>
        <x>0.2436451</x>
        <y>-0.03456776</y>
        <z>0.0332907774</z>
        <w>0.9686763</w>
        <eulerAngles>
          <x>28.3156128</x>
          <y>356.695343</y>
          <z>3.10282016</z>
        </eulerAngles>
      </Quaternion>
      <Quaternion>
        <x>-0.0274707</x>
        <y>-0.004143617</y>
        <z>0.0005820858</z>
        <w>0.9996139</w>
        <eulerAngles>
          <x>356.852</x>
          <y>359.5228</y>
          <z>0.0798406</z>
        </eulerAngles>
      </Quaternion>
    </ArrayOfQuaternion>
    <ArrayOfQuaternion>
      <Quaternion>
        <x>-0</x>
        <y>-0</y>
        <z>0.5602086</z>
        <w>0.8283516</w>
        <eulerAngles>
          <x>-0</x>
          <y>-0</y>
          <z>68.14045</z>
        </eulerAngles>
      </Quaternion>
      <Quaternion>
        <x>0</x>
        <y>0</y>
        <z>0</z>
        <w>1</w>
        <eulerAngles>
          <x>-0</x>
          <y>0</y>
          <z>0</z>
        </eulerAngles>
      </Quaternion>
      <Quaternion>
        <x>-0</x>
        <y>-0</y>
        <z>-0</z>
        <w>1</w>
        <eulerAngles>
          <x>-0</x>
          <y>0</y>
          <z>0</z>
        </eulerAngles>
      </Quaternion>
      <Quaternion>
        <x>-0.229409814</x>
        <y>0.0272422452</y>
        <z>-0.114730783</z>
        <w>0.966160357</w>
        <eulerAngles>
          <x>334.0847</x>
          <y>6.722004</y>
          <z>344.9074</z>
        </eulerAngles>
      </Quaternion>
      <Quaternion>
        <x>-0.0120867919</x>
        <y>0.009940858</y>
        <z>-0.0253626034</z>
        <w>0.9995558</w>
        <eulerAngles>
          <x>358.644348</x>
          <y>1.17417169</y>
          <z>357.0791</z>
        </eulerAngles>
      </Quaternion>
      <Quaternion>
        <x>0.243645117</x>
        <y>-0.0345677622</y>
        <z>0.03329078</z>
        <w>0.9686764</w>
        <eulerAngles>
          <x>28.3156128</x>
          <y>356.695343</y>
          <z>3.10282016</z>
        </eulerAngles>
      </Quaternion>
      <Quaternion>
        <x>-0.0274707</x>
        <y>-0.004143617</y>
        <z>0.0005820858</z>
        <w>0.9996139</w>
        <eulerAngles>
          <x>356.852</x>
          <y>359.5228</y>
          <z>0.0798406</z>
        </eulerAngles>
      </Quaternion>
    </ArrayOfQuaternion>
  </points>
</Animation>

EDIT: Figured the 'Animation' class would be useful too.

using UnityEngine;
using System.Collections.Generic;
using System.Xml.Serialization;

[XmlRoot("Animation")]
public class Animation {

    [XmlElement("nbAnimatables")]
    public int NbAnimatables { get; set; }
    [XmlElement("animationID")]
    public int AnimationID { get; set; }

    [XmlArray("points")]
    public List<Quaternion[]> Points { get; private set; }

    public Animation()
    {
    }

    public Animation(int nbAnimatables, int animationID)
    {
        this.NbAnimatables = nbAnimatables;
        this.AnimationID = animationID;
        Points = new List<Quaternion[]>();
    }

    public bool AddPoint(Quaternion[] animatableRotations)
    {
        if (animatableRotations.Length == NbAnimatables)
        {
            Points.Add(animatableRotations);
            return true;
        }
        return false;
    }

    public bool OverridePoint(Quaternion[] animatableRotations, int pointIndex)
    {
        if (pointIndex < Points.Count)
        {
            Points[pointIndex] = animatableRotations;
            return true;
        }
        return false;
    }

    public bool RemovePoint(int pointIndex)
    {
        if (pointIndex < Points.Count)
        {
            Points.RemoveAt(pointIndex);
            return true;
        }
        return false;
    }
}

Try following :

            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            XmlWriter writer = XmlWriter.Create(path, settings);
            XmlSerializer serializer = new XmlSerializer(typeof(Animation));
            serializer.Serialize(writer, animation);

I would try using StorageFile API :

Windows.Storage.StorageFolder storageFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
string fileName = baseFilename + animationID + ".xml");
Windows.Storage.StorageFile sampleFile = await storageFolder.CreateFileAsync(fileName,   Windows.Storage.CreationCollisionOption.ReplaceExisting);
using (var stream = await sampleFile.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite);)
{
    using (var outputStream = stream.GetOutputStreamAt(0))
    {
       XmlSerializer serializer = new XmlSerializer(typeof(Animation));
       serializer.Serialize(stream, animation);
       await outputStream.FlushAsync();
    }
}

More info on Create, write, and read a file for UWP Apps

Following jdweng's advice, i decided to change the way I was writing the file. I tried the StreamWriter again, and for some reason, it worked! I changed the code at line 18 by this :

        using (StreamWriter writer = new StreamWriter(File.Create(path)))
        {
            XmlSerializer serializer = new XmlSerializer(typeof(Animation));
            serializer.Serialize(writer, animation);
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM