First time playing with serialization in C#... any help would be greatly appreciated!
The following are my generic serializer and deserializer:
public static string SerializeObject<T>(T objectToSerialize)
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream memStr = new MemoryStream();
try
{
bf.Serialize(memStr, objectToSerialize);
memStr.Position = 0;
return Convert.ToBase64String(memStr.ToArray());
}
finally
{
memStr.Close();
}
}
public static T DeserializeObject<T>(string str)
{
BinaryFormatter bf = new BinaryFormatter();
byte[] b = System.Text.Encoding.UTF8.GetBytes(str);
MemoryStream ms = new MemoryStream(b);
try
{
return (T)bf.Deserialize(ms);
}
finally
{
ms.Close();
}
}
This is the object I am trying to serialize:
[Serializable()]
class MatrixSerializable : ISerializable
{
private bool markerFound;
private Matrix matrix;
public MatrixSerializable( Matrix m, bool b)
{
matrix = m;
markerFound = b;
}
public MatrixSerializable(SerializationInfo info, StreamingContext ctxt)
{
markerFound = (bool)info.GetValue("markerFound", typeof(bool));
matrix = Matrix.Identity;
if (markerFound)
{
//deserialization code
}
}
public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
{
// serialization code
}
public Matrix Matrix
{
get { return matrix; }
set { matrix = value; }
}
public bool MarkerFound
{
get { return markerFound; }
set { markerFound = value; }
}
}
And an example of how am running it:
MatrixSerializable ms = new MatrixSerializable(Matrix.Identity * 5, true);
string s = Serializer.SerializeObject<MatrixSerializable>(ms);
Console.WriteLine("serialized: " + s);
ms = Serializer.DeserializeObject<MatrixSerializable>(s);
Console.WriteLine("deserialized: " + ms.Matrix + " " + ms.MarkerFound);
When I try to run this I get an error "SerializationException was unhandled: The input stream is not a valid binary format. The starting contents (in bytes) are: 41-41-45-41-41-41-44-2F-2F-2F-2F-2F-41-51-41-41-41 ..."
Any advice on what I am doing wrong or how to fix this would be greatly appreciated!
You are using Base64 to convert byte array to string and GetUtf8 bytes to convert from string back to byte array.
Replace System.Text.Encoding.UTF8.GetBytes(str); with Convert.FromBase64String(str);
Related
Hello I want migration unity project version from 5.0.2 to 2020.x.x
when did directly migration to 2020.x.x I did run into a problem with expection
"InvalidCastException: Object must implement IConvertible."
So I did try migration Sequentially unity5 -> V2017 -> V2018 was working well
But when I migration v2019 I did run into a problem with same expection
this code is causing problems area
[System.Serializable]
public class BookStruct
{
public int ID;
public int[] PageComposition;
public int PageCount;
public string Name;
public int CoverPageID;
public int CategoryID;
public Dictionary<SystemLanguage, TextDataTemplate> dicTextData;
public int[] RecommendBookList;
public int MarketingMark;
public string RecommendAge;
public int Priority;
public bool FreeAtNow;
}
/* public static string BinaryStringFormatter(object target)
{
MemoryStream ms = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(ms, target);
return BitConverter.ToString(ms.ToArray()); // not here!
} */
public static object BinaryDeserialize(byte[] data)
{
MemoryStream ms = new MemoryStream(data);
BinaryFormatter formatter = new BinaryFormatter();
return formatter.Deserialize(ms); //here!
}
bottom code is before code
switch (Application.platform)
{
case RuntimePlatform.Android:
filepath = Application.streamingAssetsPath + "/"+bookname;
break;
default:
filepath = "file://" + Application.streamingAssetsPath + "/" + bookname;
break;
}
Debug.Log("파일 경로 확인 => " + filepath);
using (WWW www = new WWW(filepath))
{
while (!www.isDone)
{
yield return true;
}
TextAsset t = www.assetBundle.mainAsset as TextAsset;
book = (BookStruct)BK_Function.BinaryDeserialize(t.bytes);
www.assetBundle.Unload(true);
iBook.iPageCount = book.PageComposition.Length;
Debug.Log(book.dicTextData[SystemLanguage.Korean].Description);
Debug.Log("pagecount : " + book.PageCount + " // pageComposition.Length : " + book.PageComposition.Length);
}
Also,I did Debug.log file path and result is
" file://C:/unitySource/singlebook/Assets/StreamingAssets/B12_2_Cat.unity3d"
and Bookstruct is
""
Please help me (:
I am getting the error "Exception thrown: 'System.NotSupportedException' in mscorlib.ni.dll Memory stream is not expandable" when trying to serialize and save an instance of a custom class object.
Here are my saving/loading methods:
public void SerializeObject<T>(T serializableObject, string fileName)
{
if (serializableObject == null) { return; }
try
{
XmlDocument xmlDocument = new XmlDocument();
XmlSerializer serializer = new XmlSerializer(serializableObject.GetType());
using (MemoryStream stream = new MemoryStream())
{
// convert string to stream
byte[] byteArray = Encoding.UTF8.GetBytes(fileName);
MemoryStream fileNameStream = new MemoryStream(byteArray);
serializer.Serialize(stream, serializableObject);
stream.Position = 0;
xmlDocument.Load(stream);
xmlDocument.Save(fileNameStream);
stream.Dispose();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
Debug.WriteLine(TAG + serializableObject.ToString() + " saved");
}
public T DeSerializeObject<T>(string fileName)
{
if (string.IsNullOrEmpty(fileName)) { return default(T); }
T objectOut = default(T);
try
{
string attributeXml = string.Empty;
// convert string to stream
byte[] byteArray = Encoding.UTF8.GetBytes(fileName);
MemoryStream stream = new MemoryStream(byteArray);
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(stream);
string xmlString = xmlDocument.OuterXml;
using (StringReader read = new StringReader(xmlString))
{
Type outType = typeof(T);
XmlSerializer serializer = new XmlSerializer(outType);
using (XmlReader reader = XmlReader.Create(read))
{
objectOut = (T)serializer.Deserialize(reader);
reader.Dispose();
}
read.Dispose();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
if (objectOut != null) Debug.WriteLine(TAG + objectOut.ToString() + " loaded");
return objectOut;
}
And here is the object class that I'm trying to save:
public class EntryDataType
{
readonly string TAG = "EntryDataType: ";
private static int idCounter = -1;
public int id;
private EntryDataType parentEdt;
public EntryDataType parentEdtProperty
{
get { return parentEdt; }
set { parentEdt = value; }
}
// row control is not serializable, so ignore it when saving
[XmlIgnore]
public RowControl linkedRowControl;
public int indent = -1;
public int index = -1;
public int linearIndex = -1;
private bool completed = false;
public bool completedProperty {
get { return completed; }
set
{
// set hidden state and set all children's hidden state, i.e. they will do the same
completed = value;
foreach (var item in childList)
{
item.linkedRowControl.SetCompleted(value);
}
}
}
public ChildList<EntryDataType> childList;
public bool bulletButtonChecked;
public string textboxText;
public EntryDataType()
{
// assign unique id to each entry
id = idCounter;
idCounter++;
//Debug.WriteLine(TAG + "new entry " + id + " created");
childList = new ChildList<EntryDataType>();
childList.parentEdtOfChildListProperty = this;
}
}
I've already rewritten the class to eliminate it's constructor's parameters, and to ignore the unserializeable RowControl member. I am just learning .NET and c# so don't fully know what I'm doing yet; any help is greatly appreciated. Thanks :)
OK, I think I see what you are trying to do - serialize and deserialize an object to/from a file. Your way is a bit complicated, it could be simplified, for example like this:
public static void SerializeObject<T>(T serializableObject, string fileName)
{
if (serializableObject == null) { return; }
try
{
XmlSerializer serializer = new XmlSerializer(serializableObject.GetType());
using (Stream stream = File.Open(fileName, FileMode.Create))
{
serializer.Serialize(stream, serializableObject);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
public static T DeSerializeObject<T>(string fileName)
{
if (string.IsNullOrEmpty(fileName)) { return default(T); }
try
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (Stream stream = File.Open(fileName, FileMode.Open))
{
return (T)serializer.Deserialize(stream);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
return default(T);
}
There is no need to read/write to a MemoryStream first. You can serialize and deserialize straight from the file.
Also, when using using, there is no need to dispose the object (like your stream.Dispose(); line) - that's what the dispose is for (with the added bonus that if there's an exception, the object will be disposed as well).
I haven't tried this with your class but it should work fine. Give it a try and see if it works.
byte[] byteArray = Encoding.UTF8.GetBytes(fileName);
MemoryStream fileNameStream = new MemoryStream();
...
xmlDocument.Save(fileNameStream);
Is there possible to writte protobuf serialized content directly to SharpZipLib stream? When I try to do this, looks like the provided stream is not filled with the data from protobuf. Later I would need to get back the deserialized entity from provided Zip stream.
My code looks like this:
private byte[] ZipContent(T2 content)
{
const short COMPRESSION_LEVEL = 4; // 0-9
const string ENTRY_NAME = "DefaultEntryName";
byte[] result = null;
if (content == null)
return result;
IStreamSerializerProto<T2> serializer = this.GetSerializer(content.GetType());
using (MemoryStream outputStream = new MemoryStream())
{
using (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream))
{
zipOutputStream.SetLevel(COMPRESSION_LEVEL);
ZipEntry entry = new ZipEntry(ENTRY_NAME);
entry.DateTime = DateTime.Now;
zipOutputStream.PutNextEntry(entry);
serializer.Serialize(zipOutputStream, content);
}
result = outputStream.ToArray();
}
return result;
}
private class ProtobufStreamSerializer<T3> : IStreamSerializerProto<T3>
{
public ProtobufStreamSerializer()
{
ProtoBuf.Serializer.PrepareSerializer<T3>();
}
public void Serialize(Stream outputStream, T3 content)
{
Serializer.Serialize(outputStream, content);
}
public T3 Deserialize(Stream inputStream)
{
T3 deserializedObj;
using (inputStream)
{
deserializedObj = ProtoBuf.Serializer.Deserialize<T3>(inputStream);
}
return deserializedObj;
}
}
Sample of a class which I'm trying to serialize:
[Serializable]
[ProtoContract]
public class Model
{
[XmlElement("ModelCode")]
[ProtoMember(1)]
public int ModelCode { get; set; }
...
}
This is the problem, I believe (in the original code in the question):
public void Serialize(Stream outputStream, T3 content)
{
using (var stream = new MemoryStream())
{
Serializer.Serialize(stream, content);
}
}
You're completely ignoring outputStream, instead writing the data just to a new MemoryStream which is then ignored.
I suspect you just want:
public void Serialize(Stream outputStream, T3 content)
{
Serializer.Serialize(outputStream, content);
}
I'd also suggest removing the using statement from your Deserialize method: I'd expect the caller to be responsible for disposing of the input stream when they're finished with it. Your method can be simplified to:
public T3 Deserialize(Stream inputStream)
{
return ProtoBuf.Serializer.Deserialize<T3>(inputStream);
}
The code (with the edit pointed out by Jon) looks fine. Here it is working:
static void Main()
{
var obj = new Bar{ X = 123, Y = "abc" };
var wrapper = new Foo<Bar>();
var blob = wrapper.ZipContent(obj);
var clone = wrapper.UnzipContent(blob);
}
where Bar is:
[ProtoContract]
class Bar
{
[ProtoMember(1)]
public int X { get; set; }
[ProtoMember(2)]
public string Y { get; set; }
}
and Foo<T> is your class (I didn't know the name), where I have added:
public T2 UnzipContent(byte[] data)
{
using(var ms = new MemoryStream(data))
using(var zip = new ZipInputStream(ms))
{
var entry = zip.GetNextEntry();
var serializer = this.GetSerializer(typeof(T2));
return serializer.Deserialize(zip);
}
}
Also, note that compression is double-edged. In the example I give above, the underlying size (i.e. if we just write to a MemoryStream) is 7 bytes. ZipInputStream "compresses" this 7 bytes down to 179 bytes. Compression works best on larger objects, usually when there is lots of text content.
I'm trying to deserialize file by using DataContractSerializer. I have such class:
[DataContract]
public class kontenerUstawienia
{
[DataMember]
public int[] stanGry;
[DataMember]
public int maxSize;
[DataMember]
public int[] stanOpcji;
[DataMember]
public int numerFlagi1;
[DataMember]
public int numerFlagi2;
public kontenerUstawienia()
{
}
(...)
}
Inside, after saving serialized class instance to the file, I read the file and try to deserialize:
try
{
zapiszObiektUstawien((kontenerUstawienia)deserializer.ReadObject(strumien));
}
catch (SerializationException e)
{
System.Diagnostics.Debug.WriteLine("\n\n\n\n++++++\n" +
e.Message
+ "\n+++++++++++++++++++++++++++++++++++++++++++++++");
}
catch prints me:
++++++
There was an error deserializing the object of type
WindowsPhoneGame1.kontenerUstawienia. There are multiple root elements. Line 1,
position 599.
+++++++++++++++++++++++++++++++++++++++++++++++
What am I doing wrong?
EDIT:
Here is code that I serialize and save:
public void zapiszDoPliku(string sciezkaDoPliku, IsolatedStorageFile katalog)
{
IsolatedStorageFileStream strumien = katalog.CreateFile(sciezkaDoPliku); // tworzenie pliku
MemoryStream ms = new MemoryStream();
StreamReader r = new StreamReader(ms);
DataContractSerializer serializer = new DataContractSerializer(typeof(kontenerUstawienia));
serializer.WriteObject(ms, this);
ms.Position = 0;
string daneDoZapisania = r.ReadToEnd();
byte[] bytes = Encoding.Unicode.GetBytes(daneDoZapisania);
strumien.Write(bytes, 0, bytes.Length);
ms.Close();
strumien.Close();
}
EDIT2:
File saved:
File is here
Are you sure that the file was empty before writing?
I have been using some code to create MTOM by using code from MSDN.
It seems that there is an error and I cannot understand where the problem lies as one of the users on the forum pointed out that there is an error.
The file (JPEG) data get corrupted after a de-serialization. The complete code is listed below.
public class Post_7cb0ff86_5fe1_4266_afac_bcb91eaca5ec
{
[DataContract()]
public partial class TestAttachment
{
private byte[] fileField;
private string filenameField;
[DataMember()]
public byte[] File
{
get
{
return this.fileField;
}
set
{
this.fileField = value;
}
}
[DataMember()]
public string Filename
{
get
{
return this.filenameField;
}
set
{
this.filenameField = value;
}
}
}
public static void Test()
{
string Filename = "Image.jpg";
byte[] file = File.ReadAllBytes(Filename);
TestAttachment Attachment = new TestAttachment();
Attachment.Filename = Filename;
Attachment.File = file;
MemoryStream MTOMInMemory = new MemoryStream();
XmlDictionaryWriter TW = XmlDictionaryWriter.CreateMtomWriter(MTOMInMemory, Encoding.UTF8, Int32.MaxValue, "");
DataContractSerializer DCS = new DataContractSerializer(Attachment.GetType());
DCS.WriteObject(TW, Attachment);
TW.Flush();
Console.WriteLine(Encoding.UTF8.GetString(MTOMInMemory.ToArray()));
var v = DeserializeMTOMMessage(Encoding.UTF8.GetString(MTOMInMemory.ToArray()));
File.WriteAllBytes(v.Filename,v.File);
}
public static TestAttachment DeserializeMTOMMessage(string MTOMMessage)
{
try
{
MemoryStream MTOMMessageInMemory = new MemoryStream(UTF8Encoding.UTF8.GetBytes(MTOMMessage));
XmlDictionaryReader TR = XmlDictionaryReader.CreateMtomReader(MTOMMessageInMemory, Encoding.UTF8, XmlDictionaryReaderQuotas.Max);
DataContractSerializer DCS = new DataContractSerializer(typeof(TestAttachment));
return (TestAttachment)DCS.ReadObject(TR);
}
catch
{
return null;
}
}
}
I would be grateful if someone can help me in pointing out where the problem is. I am new to XOP/MTOM and find it hard to track down where the error might be. Either serialization or de-serialization.
Thank you
There's a bug in your code.
Change your method call
MTOMInMemory.Position = 0;
DeserializeMTOMMessage(Encoding.UTF8.GetString(MTOMInMemory.ToArray()));
to
DeserializeMTOMMessage(MTOMInMemory.ToArray())
and the implementation to
public static TestAttachment DeserializeMTOMMessage(byte[] MTOMMessage)
{
try
{
MemoryStream MTOMMessageInMemory = new MemoryStream(MTOMMessage);
XmlDictionaryReader TR = XmlDictionaryReader.CreateMtomReader(MTOMMessageInMemory, Encoding.UTF8, XmlDictionaryReaderQuotas.Max);
DataContractSerializer DCS = new DataContractSerializer(typeof(TestAttachment));
return (TestAttachment)DCS.ReadObject(TR);
}
catch
{
return null;
}
}
what you've done was some double conversion from utf8 to byte array and vice versa, which ended up creating not the original byte array you were using