Unity 5 C# script to write to a binary data file- getting a null reference exception and a IOException: sharing violation
Hoping for some help here -- pulled enough hair I am crying "Uncle"
I keep getting two errors; neither of which I seem to be able to resolve myself.
First is a warning about a Null Reference Exception error on the fourth line under ToBinaryDataFile() ("gsaver.NumberPlayers = dataManager.Load("NUMBEROFPLAYERSPLAYING").ToString();"). http://prntscr.com/95v5eq. I also get a IOException:Sharing violation http://prntscr.com/95v6lz.
A file is created, but it appears to be of zero length and have nothing inside.
I know all the routines function with the exception of ToBinaryDataFile() and FromBinaryDataFile().
I left the others included mostly as an aide to others that might like to see how I did those (and in case they have some impact somehow).
using UnityEngine;
using System.Collections;
using System;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
[Serializable]
public class GameInformation : MonoBehaviour
{
public static string NumberPlayers { get; set; }
public static string CurrentPlayer { get; set; }
public static string CurrentPlayerPhase { get; set; }
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
}
}
// Added the class below as I could not seem to get the static version above to work; so for purposes of writing to a file I use this redundent non-static class.
[Serializable]
public class SGameInformation
{
public string NumberPlayers;
public string CurrentPlayer;
public string CurrentPlayerPhase;
}
public class SaveInformation
{
public static void ToPreferences()
{
PlayerPrefs.SetString("NUMBEROFPLAYERSPLAYING", GameInformation.NumberPlayers);
PlayerPrefs.SetString("CURRENTPLAYER", GameInformation.CurrentPlayer);
PlayerPrefs.SetString("CURRENTPLAYERPHASE", GameInformation.CurrentPlayerPhase);
}
public static void ToBinaryDataFile()
{
BinaryFormatter binary = new BinaryFormatter();
FileStream fStream = File.Create(Application.persistentDataPath + "/saveFile.hag");
SGameInformation gsaver = new SGameInformation() as SGameInformation;
gsaver.NumberPlayers = dataManager.Load("NUMBEROFPLAYERSPLAYING").ToString();
gsaver.CurrentPlayer = dataManager.Load("CURRENTPLAYER").ToString();
gsaver.CurrentPlayerPhase = dataManager.Load("CURRENTPLAYERPHASE").ToString();
//Tried with and without the following line -- another thread suggested it.
//Environment.SetEnvironmentVariable("MONO_REFLECTION_SERIALIZER", "yes");
binary.Serialize(fStream, gsaver);
fStream.Close();
}
}
public class LoadInformation
{
public static void FromPreferences()
{
GameInformation.NumberPlayers = PlayerPrefs.GetString("NUMBEROFPLAYERSPLAYING", "Two");
GameInformation.CurrentPlayer = PlayerPrefs.GetString("CURRENTPLAYER", "1");
GameInformation.CurrentPlayer = PlayerPrefs.GetString("CURRENTPLAYERPHASE", "1");
}
public static void FromBinaryDataFile()
{
if (File.Exists(Application.persistentDataPath + "/saveFile.hag"))
{
BinaryFormatter binary = new BinaryFormatter();
FileStream fStream = File.Open(Application.persistentDataPath + "/saveFile.hag", FileMode.Open);
var gloader = (SGameInformation)binary.Deserialize(fStream) as SGameInformation;
fStream.Close();
dataManager.Save("NUMBEROFPLAYINGSPLAYING",gloader.NumberPlayers);
dataManager.Save("CURRENTPLAYER", gloader.CurrentPlayer);
dataManager.Save("CURRENTPLAYERPHASE", gloader.CurrentPlayerPhase);
}
}
}
public class dataManager
{
public static BinaryFormatter binaryFormatter = new BinaryFormatter();
public static void Save (string saveTag, object obj)
{
MemoryStream memoryStream = new MemoryStream();
binaryFormatter.Serialize(memoryStream, obj);
string temp = System.Convert.ToBase64String(memoryStream.ToArray());
PlayerPrefs.SetString(saveTag, temp);
}
public static object Load(string saveTag)
{
string temp = PlayerPrefs.GetString(saveTag);
if (temp == string.Empty)
{
return null;
}
MemoryStream memoryStream = new MemoryStream(System.Convert.FromBase64String(temp));
return binaryFormatter.Deserialize(memoryStream);
}
}
Would appreciate responses that resolve the above code. I like how I have it organized -- if only it worked(!).
First off I would add some logging so I could see what's failing.
And when you have a function that can return null (such as data$$anonymous$$anager.Load) you should check its return value before using it. You've set your load function up to fail silently, returning null if PlayPrefs doesn't have an entry for the tag you're after. But then you use the return value (on the line that's throwing the NRE) without checking it. That looks like a possible source of the problem.
Is the difference intentionally? line 59: "NU$$anonymous$$BEROFPLAYERSPLAYING"
line 73: "NU$$anonymous$$BEROFPLAYINGSPLAYING"
@saschandriod: Ugh, was really hoping that mistake would fix it, but I made the change and it did not. I am still getting both errors. Of course, it would have caused problems in use so thank you very much because I never saw it and doubt I would ever have heh!
@Bonfire boy: I'll try to check the return value and respond with results.
@Uproar I've converted your answer to a comment - it wasn't answering the question and belongs in this thread with what it's replying to.
A tip for avoiding that kind of error is to store the key string in a variable so you only have to type it out once and you know it'll always be the same.
So
const string numPlaying$$anonymous$$ey = "NU$$anonymous$$BEROFPLAYERSPLAYING";
and then
PlayerPrefs.SetString(numPlaying$$anonymous$$ey, GameInformation.NumberPlayers);
data$$anonymous$$anager.Save(numPlaying$$anonymous$$ey,gloader.NumberPlayers);
and so on
Answer by Uproar · Nov 24, 2015 at 09:57 PM
@Bonfire Boy Thank you, I am new to both C# and Unity so appreciate such tips; I'll try to incorporate that in the future. Here is the solution I came up with (avoided dataManager() as it was throwing back nulls. Didn't really need it (and don't really understand it I suspect).
public class SaveInformation
{
public static void ToGameInformation(string saveTag, object obj)
{
switch (saveTag)
{
case "NUMBEROFPLAYERSPLAYING":
GameInformation.NumberPlayers = (string)obj;
PlayerPrefs.SetString("NUMBEROFPLAYERSPLAYING", GameInformation.NumberPlayers);
break;
case "CURRENTPLAYER":
GameInformation.CurrentPlayer = (string)obj;
PlayerPrefs.SetString("CURRENTPLAYER", GameInformation.CurrentPlayer);
break;
case "CURRENTPLAYERPHASE":
GameInformation.CurrentPlayerPhase = (string)obj;
PlayerPrefs.SetString("CURRENTPLAYERPHASE", GameInformation.CurrentPlayerPhase);
break;
default:
Debug.Log("Error - Unrecognized tag <" + saveTag + ">.");
break;
}
}
public static void ToBinaryDataFile()
{
BinaryFormatter binary = new BinaryFormatter();
FileStream fStream = File.Create(Application.persistentDataPath + "/saveFile.bin");
SGameInformation gsaver = new SGameInformation();
if (LoadInformation.FromGameInformation("NUMBEROFPLAYERSPLAYING") != null)
{
gsaver.NumberPlayers = LoadInformation.FromGameInformation("NUMBEROFPLAYERSPLAYING").ToString();
if (LoadInformation.FromGameInformation("CURRENTPLAYER") != null)
{
gsaver.CurrentPlayer = LoadInformation.FromGameInformation("CURRENTPLAYER").ToString();
if (LoadInformation.FromGameInformation("CURRENTPLAYERPHASE") != null)
{
gsaver.CurrentPlayerPhase = LoadInformation.FromGameInformation("CURRENTPLAYERPHASE").ToString();
Environment.SetEnvironmentVariable("MONO_REFLECTION_SERIALIZER", "yes");
binary.Serialize(fStream, gsaver);
}
}
}
fStream.Close();
}
}
public class LoadInformation
{
public static object FromGameInformation(string saveTag)
{
switch (saveTag)
{
case "NUMBEROFPLAYERSPLAYING":
return GameInformation.NumberPlayers;
case "CURRENTPLAYER":
return GameInformation.CurrentPlayer;
case "CURRENTPLAYERPHASE":
return GameInformation.CurrentPlayerPhase;
default:
Debug.Log("Error - Unrecognized tag <" + saveTag + "> in switch() statement #1.");
break;
}
return null;
}
public static void FromBinaryDataFile()
{
if (File.Exists(Application.persistentDataPath + "/saveFile.bin"))
{
BinaryFormatter binary = new BinaryFormatter();
FileStream fStream = File.Open(Application.persistentDataPath + "/saveFile.bin", FileMode.Open);
var gloader = (SGameInformation)binary.Deserialize(fStream) as SGameInformation;
fStream.Close();
SaveInformation.ToGameInformation("NUMBEROFPLAYERSPLAYING", gloader.NumberPlayers);
SaveInformation.ToGameInformation("CURRENTPLAYER", gloader.CurrentPlayer);
SaveInformation.ToGameInformation("CURRENTPLAYERPHASE", gloader.CurrentPlayerPhase);
SaveInformation.ToPreferences();
}
}
P.S. Can't seem to reply to your comments... so did answer again. Won't submit otherwise.
Your answer
![](https://koobas.hobune.stream/wayback/20220612050040im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
When writing a txt file, it says sharing violation 1 Answer
SerializationException errors!! & IOException. BinaryFormatter problems 1 Answer
How to tell if an audio source is not currently playing sound 1 Answer
How to call a function every second ? 1 Answer
Destroying child gameobject of animated parent messes up other child gameobject animations. 0 Answers