Hey guys, so i wrote this passage here for my study:
#pragma strict
import System.Xml;
import System.IO;
//private var record: boolean = false;
//private var fileOpen : boolean = false;
private var fileName : String;
private var myFile : XmlWriter;
//private var nextWrite: float = 0;
function Start () {
//Dateinamen festlegen
fileName = Path.Combine(Application.persistentDataPath, "myXml.xml");
}
function Update () {
//Die Einrueckung festlegen
var settings : XmlWriterSettings = new XmlWriterSettings();
settings.Indent = true;
//Datei erstellen
myFile = XmlWriter.Create(fileName, settings);
//den Prolog erzeugen lassen
myFile.WriteStartDocument();
//Wurzelelement
myFile.WriteStartElement("Testeintraege");
//Element Test erzeugen
myFile.WriteStartElement("Test");
//Unterelemente
myFile.WriteElementString("A", "Das ist ein Test");
myFile.WriteElementString("B", "Das hier ist ein zweiter Test.");
//Element Test schlieĂźen
myFile.WriteEndElement();
//AbschlieĂźen
myFile.WriteEndDocument();
}
now, since unity doesnt throw any mistakes, i’d think the script is fine. But - having put it on a game object and started the game within unity - i dont find the file myXml.xml anywhere.
could it be that when run within unity itself the file isn’t created? or where did i make a mistake?
Are you using a PC or a Mac? Or is this on the device? You’re using persistentDataPath which will be different depending on your platform. For instance, on PC the file would be written to:
c:\users\yourusername\AppData\LocalLow\company\game where company and game are setup in the Player Settings.
FIrst I’ll say Update is the worst place to put this. You’re telling it to create your file once every frame. So you’re constantly recreating the file over and over.
Second, (and @Dustin-Horne beat me to it) what are you building on?
I am, of course, assuming your xml is also correct as I haven’t used it since switching to json.
ah yes, update IS the worst place. thanks for that.
i am using a win7 pc.
but under the named location (appdata\local) there is no “DefaultCompany” (standard if not changed) and even searching there would not bring up the xml file.
i also checked in the registry - no luck.
I’ve never been a big fan of using the Document style of writing and reading XML files. I find it so much easier to create a data class, fill that data class with the the data you need and Serialize it using a Binary Writer. And of course you Deserialize the data into the same class. Here is what you need:
Create a script for the XML Serializer/Deserializer… You will use this for all your Data Classes. It never gets attached to a Game Object just sits in your Project:
using UnityEngine;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
public static class XMLOP {
public static void Serialize(object item, string path)
{
XmlSerializer serializer = new XmlSerializer(item.GetType());
StreamWriter writer = new StreamWriter(path);
serializer.Serialize(writer.BaseStream, item);
writer.Close();
}
public static T Deserialize<T>(string path)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
StreamReader reader = new StreamReader(path);
T item = (T)serializer.Deserialize(reader.BaseStream);
reader.Close();
return item;
}
}
Now for each Set of Data you want to put into a XML File. You need to create an new Script. These Data Objects will also never be attached to a Game Object. Here is an Example one:
using UnityEngine;
using System.Xml;
using System.Xml.Serialization;
using System.Collections.Generic;
[XmlRoot("RootName")]
public class XMLData {
// Make all the data you want in the XML file
// Public Fields
public string someString;
public Vector3 myVector;
[XmlArray("ArrayName"), XmlArrayItem("ArrayItemName")]
public SomeOtherClass[] someOtherClass;
// this function will always look like this
public void Save(string path)
{
XMLOP.Serialize(this, path);
}
// You need to write this function yourself to populate
// the data. Your just basically copying all the fields
// you read out of the Deserializer, and copy them into the current object
public void Load(string path)
{
XMLData info = XMLOP.Deserialize<XMLData>(path);
this.someString = info.someString;
this.myVector = info.myVector;
this.someOtherClass = new SomeOtherClass[info.someOtherClass.Length];
for (int i = 0; i < someOtherClass.Length; i++)
this.someOtherClass[i] = info.someOtherClass[i];
}
}
public class SomeOtherClass
{
public int someInt;
public float someFloat;
public bool someBool;
}
Then you just need an a script to load this data and use it in Unity. Create this Script and attach it to a Game Object.
IF you copied the above scripts into your project you should be able to just press play. IT will create an XML File and Read it back out and display one of the variables:
using UnityEngine;
using System.Collections;
using System.IO;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Reflection;
using System;
public class XMLLoader : MonoBehaviour
{
XMLData data;
XMLData newData;
void Awake()
{
data = new XMLData();
newData = new XMLData();
}
void Start()
{
// Create an XML File based on the what we store in the data object
WriteXMLFile();
// Read it back out into newData
newData.Load(Path.Combine(Application.dataPath, "testXml.xml"));
Debug.Log("This should print 3.14159: " + newData.someOtherClass[1].someFloat);
}
void WriteXMLFile()
{
// Ideally you would Write your XML with a separate editor program you write
// That uses this same XMLData class. This is just for example purposes.
data.someString = "TestString";
data.myVector = new Vector3(1.0f, 2.0f, 3.0f);
data.someOtherClass = new SomeOtherClass[2];
data.someOtherClass[0] = new SomeOtherClass();
data.someOtherClass[1] = new SomeOtherClass();
data.someOtherClass[0].someInt = 5;
data.someOtherClass[0].someFloat = 4.5f;
data.someOtherClass[0].someBool = false;
data.someOtherClass[1].someInt = 10;
data.someOtherClass[1].someFloat = 3.14159f;
data.someOtherClass[1].someBool = true;
// this will save it to your projects Asset Directory
data.Save(Path.Combine(Application.dataPath, "testXml.xml"));
}
}
This, and also, for the love of pete, use a “using” statement. XmlWriter is IDisposable. You’re going to end up with a hanging handle to your file and have it be locked.
//Die Einrueckung festlegen
var settings : XmlWriterSettings = new XmlWriterSettings();
settings.Indent = true;
//Datei erstellen
using(var myFile = XmlWriter.Create(fileName, settings))
{
//den Prolog erzeugen lassen
myFile.WriteStartDocument();
//Wurzelelement
myFile.WriteStartElement("Testeintraege");
//Element Test erzeugen
myFile.WriteStartElement("Test");
//Unterelemente
myFile.WriteElementString("A", "Das ist ein Test");
myFile.WriteElementString("B", "Das hier ist ein zweiter Test.");
//Element Test schlieĂźen
myFile.WriteEndElement();
//AbschlieĂźen
myFile.WriteEndDocument();
myFile.Close(); //Close it
}
THIS one did the trick, thanks so much for the suggest. i knew i had to close the file because of my old Java background, but misread my books in thiinking that the file would be closed with the command i mentioned earlier.
if you have the patience with me, i’d like to learn more every day, so i’ll just ask; what do you mean by
just WOW, thanks so much for the efford, i’ll be dead honest: i don’t FULLY understand (mostly because of my lack of term vocabulary) but i’ll try to get into your suggestion line by line.
Some things hold handles to unmanaged resources, or need to do some cleanup. These classes implement the IDisposable interface. XmlWriter is one such class because it holds a handle to a file. If you don’t dispose it class it may hang on to that file handle and potentially prevent subsequent writes to the file.
You can manually call Dispose yourself, like writer.Dispose(); and this is ok, but if an exception is thrown before that dispose is called, then the object will never get disposed. By wrapping it in a using block, the CLR automatically treats it as a try/catch and will automatically call Dispose for you in the event of an exception. So take this example:
//This line returns a FileStream which is IDisposable
var someFile = File.Open(someFilePath);
//This line will throw a DivideByZeroException;
var z = 75 / 0;
//This line will never get called because of the exception above
someFile.Dispose();
Now, here is a similar case that shows the benefit:
using(var someFile = File.Open(somePath))
{
//This will still throw the DivideByZeroException...
var z = 75 / 0;
//...no need to do anything else, the "using" block will automatically still call Dispose on the file stream.
}