How to export a class in a binary file - c#

I need to export into a binary file an observable collection. This file will be parsed by an embeded software.
This is my class of Led configuration :
[XmlRoot("ConfLed")]
public class LedVals
{
#region Properties
[XmlAttribute]
public int ID { get; set; }
[XmlAttribute]
public string Type { get; set; } = "Trigger";
[XmlAttribute]
public string Binding { get; set; } = "OFF";
[XmlAttribute]
public int Trigger1 { get; set; } = 0;
[XmlAttribute]
public int Trigger2 { get; set; } = 0;
[XmlAttribute]
public string ColorT0 { get; set; } = "#000000";
[XmlAttribute]
public string ColorT1 { get; set; } = "#000000";
[XmlAttribute]
public string ColorT2 { get; set; } = "#000000";
#endregion
public LedVals()
{
}
public LedVals(int idParam, string typeParam, string bindingParam, int trig1Param, int trig2Param, string c0Param, string c1Param, string c2Param)
{
this.ID = idParam;
this.Type = typeParam;
this.Binding = bindingParam;
this.Trigger1 = trig1Param;
this.Trigger2 = trig2Param;
this.ColorT0 = c0Param;
this.ColorT1 = c1Param;
this.ColorT2 = c2Param;
}
}
And this is my serialize function for the observable collection of LedVals class (ListeLedTable) that I need to export:
public void SerializeLedTable(string filePathParam)
{
try
{
using (Stream mstream = File.Open(filePathParam + ".bin", FileMode.Create))
{
BinaryFormatter bin = new BinaryFormatter();
bin.Serialize(mstream, ListeLedTable);
}
}
}
The result is a file with binary values of the class properties and text description of the observable collection structure.
Is there a way to export properties values of a class like this ?
I can use a binaryWriter to write each property of my class in a loop, but I thought there might a simpler solution.
Thank you !

Use Marshal Techniques :
class Program
{
static void Main(string[] args)
{
LedVals ledVals = new LedVals();
int size = Marshal.SizeOf(ledVals); ;
IntPtr ptr = Marshal.AllocHGlobal(size);
byte[] buffer = new byte[Marshal.SizeOf(ledVals)];
Marshal.StructureToPtr(ledVals, ptr, true);
Marshal.Copy(ptr, buffer, 0, Marshal.SizeOf(ledVals));
Marshal.FreeHGlobal(ptr);
FileStream stream = File.OpenWrite("FILENAME");
BinaryWriter bWriter = new BinaryWriter(stream, Encoding.UTF8);
bWriter.Write(buffer);
}
}
[StructLayout(LayoutKind.Sequential)]
public class LedVals
{
public int ID { get; set; }
}

Using .NET binary serialization for any interop is a bad idea.
XML might be a better choice, but embedded devices usually lack the required horsepower to do any XML processing. I don't know what your embedded platform is, but there's a chance you could use Protocol Buffers (Protocol Buffers) to transfer binary data back and forth.

Related

C# receiving json string but unable to deserialize it

i have an application that has to deserialize an array of data wrapped in a "results" Root Object, using Netwonsoft.Json package from NuGet
The Json string is exactly this:
{"results":[{"Coin":"SBD","LP":0.000269,"PBV":-54.36,"MACD1M":true,"MACD30M":true,"MACD1H":true,"MACD1D":true},{"Coin":"XMR","LP":0.027135,"PBV":11.44,"MACD1M":true,"MACD30M":true,"MACD1H":true,"MACD1D":true}]}
This Json string is created from a Console App i made, i wanted it to look like this https://bittrex.com/Api/v2.0/pub/market/GetTicks?marketName=BTC-NEO&tickInterval=hour
My class looks like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WindowsFormsApp2
{
public class Result
{
public string Coins { get; set; }
public decimal LastPrice { get; set; }
public decimal PercentBuyVolume { get; set; }
}
public class RootObject
{
public List<Result> results { get; set; }
}
}
In the Main form i have a function to download from a URL that Json (i have XAMPP running Apache) and deserialize it in an array. And it looks like this:
private void DownloadBittrexData()
{
int PanelID = 0;
var Coin = new List<string>();
var LastPrice = new List<decimal>();
var PercentBuyVolume = new List<decimal>();
var MACD1M = new List<bool>();
var MACD30M = new List<bool>();
var MACD1H = new List<bool>();
var MACD1D = new List<bool>();
var client = new WebClient();
var URL = client.DownloadString("http://localhost/test.json");
Console.WriteLine("Json String from URL: " + URL);
var dataDeserialized = JsonConvert.DeserializeObject<RootObject>(URL);
foreach (var data in dataDeserialized.results)
{
Coin.Add(data.Coins);
LastPrice.Add(data.LastPrice);
PercentBuyVolume.Add(data.PercentBuyVolume);
}
int sizeOfArrayClose = Coin.Count - 1;
for (int i = 0; i <= sizeOfArrayClose; i++)
{
Console.WriteLine("Coin: " + Coin[i]);
Console.WriteLine("Lastprice: " + LastPrice[i]);
Console.WriteLine("PBV: " + PercentBuyVolume[i]);
}
}
Newtonsoft.Json is of course declared at the beginning of the form together with System.Net
using System.Net;
using Newtonsoft.Json;
The output looks like this:
Json String from URL: {"results":[{"Coin":"SBD","LP":0.000269,"PBV":-54.36,"MACD1M":true,"MACD30M":true,"MACD1H":true,"MACD1D":true},{"Coin":"XMR","LP":0.027135,"PBV":11.44,"MACD1M":true,"MACD30M":true,"MACD1H":true,"MACD1D":true}]}
Coin:
Lastprice: 0
PBV: 0
Coin:
Lastprice: 0
PBV: 0
It's like it fails to deserialize it after downloading it.
What should i do? Thank you very much.
Your property names don't map to the field names in the JSON. You could rename your C# properties to match the JSON, but it would make for unreadable downstream code.
Instead, you should map your properties (with nice, readable names) to the names that appear in the JSON, using JsonPropertyAttribute:
public class Result
{
public string Coin { get; set; } //didn't bother here: changed property name to Coin
[JsonProperty("LP")]
public decimal LastPrice { get; set; }
[JsonProperty("PBV")]
public decimal PercentBuyVolume { get; set; }
}
your model should be like this for deserialize json
public class Result
{
public string Coin { get; set; }
public double LP { get; set; }
public double PBV { get; set; }
public bool MACD1M { get; set; }
public bool MACD30M { get; set; }
public bool MACD1H { get; set; }
public bool MACD1D { get; set; }
}
public class RootObject
{
public List<Result> results { get; set; }
}
LastPrice and PercentBuyVolume are not available in your model that's the reason it's getting an error.
I tried your exact code on my system and I was able to retrieve the result as expected. Hope this helps, It's easy to understand.
Here is the main class
static void Main(string[] args)
{
RootObject configfile = LoadJson();
foreach (var tResult in configfile.results)
{
Console.WriteLine("Coin: " + tResult.Coin);
Console.WriteLine("Lastprice: " + tResult.LP);
Console.WriteLine("PBV: " + tResult.PBV);
}
Console.ReadLine();
}
LoadJson Function would be
private static RootObject LoadJson()
{
string json = "{\"results\":[{\"Coin\":\"SBD\",\"LP\":0.000269,\"PBV\":-54.36,\"MACD1M\":true,\"MACD30M\":true,\"MACD1H\":true,\"MACD1D\":true},{\"Coin\":\"XMR\",\"LP\":0.027135,\"PBV\":11.44,\"MACD1M\":true,\"MACD30M\":true,\"MACD1H\":true,\"MACD1D\":true}]}";
RootObject configs = Deserialize<RootObject>(json);
return configs;
}
and Deserialize function would be
private static T Deserialize<T>(string json)
{
T unsecureResult;
string _DateTypeFormat = "yyyy-MM-dd HH:mm:ss";
DataContractJsonSerializerSettings serializerSettings = new DataContractJsonSerializerSettings();
DataContractJsonSerializer serializer;
MemoryStream ms;
unsecureResult = default(T);
serializerSettings.DateTimeFormat = new System.Runtime.Serialization.DateTimeFormat(_DateTypeFormat);
serializer = new DataContractJsonSerializer(typeof(T));
ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
unsecureResult = (T)serializer.ReadObject(ms);
return unsecureResult;
}
and Now your Datamodel would be
public class Result
{
public string Coin { get; set; }
public double LP { get; set; }
public double PBV { get; set; }
public bool MACD1M { get; set; }
public bool MACD30M { get; set; }
public bool MACD1H { get; set; }
public bool MACD1D { get; set; }
}
public class RootObject
{
public List<Result> results { get; set; }
}

Ignore a class property with marshalling

I need to export an ObservableCollection of this class to a binary file:
[StructLayout(LayoutKind.Sequential)]
[XmlRoot("RxFrame")]
public class RxFrame : BaseClass
{
[XmlAttribute]
public string ID { get; set; } = "00000000";
[XmlAttribute]
public int IntVal{ get; set; } = 0;
[XmlAttribute]
public bool IsExtended { get; set; } = false;
public RxFrame()
{
}
}
and this is the function to export the data to binary:
[StructLayout(LayoutKind.Sequential)]
public class BaseClass
{
public BaseClass()
{ }
public virtual byte[] getBinaryData()
{
int size = Marshal.SizeOf(this);
IntPtr ptr = Marshal.AllocHGlobal(size);
byte[] buffer = new byte[Marshal.SizeOf(this)];
Marshal.StructureToPtr(this, ptr, false);
Marshal.Copy(ptr, buffer, 0, Marshal.SizeOf(this));
Marshal.FreeHGlobal(ptr);
return buffer;
}
}
And this is the loop over each element:
using (FileStream mstream = File.Open(filePathParam + "RX.bin", FileMode.Create))
{
BinaryWriter bWriter = new BinaryWriter(mstream, Encoding.UTF8);
bWriter.Write(ListeRxFrames.Count);
foreach (RxFrame rx in ListeRxFrames)
{
bWriter.Write(rx.getBinaryData());
}
bWriter.Close();
}
This is working fine, but I only need to export the IntVal and IsExtended properties of the RxFrame class to binary. How do I do this?
There's no way to ignore a field when marshaling the object. Maybe you need to create a separate class for the data you want to marshal.

Deserialisation unable to list data

I am trying to create an application that can both serialise and deserialise data, i can serialise the information however when i try to read the information i am left with an empty list and i do not know why.
My Serialization class
[Serializable()]
public class FileSerilizeObject
{
public static string FileName { get; set; }
public static string Extension { get; set; }
public static string Base64 { get; set; }
public FileSerilizeObject(string filename, string extension, string base64vaulue)
{
FileName = filename;
Extension = extension;
Base64 = base64vaulue;
}
}
}
My serialization/deserialization methods
public void Serialize(List<FileSerilizeObject> List)
{
using (Stream stream = File.Open(savepath, FileMode.OpenOrCreate))
{
BinaryFormatter bin = new BinaryFormatter();
bin.Serialize(stream, List);
stream.Close();
}
}
public List<FileSerilizeObject> Deserialised(string OpenPath)
{
List<FileSerilizeObject> defo;
using(Stream stream = File.Open(OpenPath, FileMode.Open))
{
BinaryFormatter bin = new BinaryFormatter();
defo = (List<FileSerilizeObject>)bin.Deserialize(stream);
}
return defo;
}
I have checked to insure that the file paths are correct and that the file itself is not empty.Everything is fine however the "defo" list is always empty so i can only assume the issue is with the defo = (List<FileSerilizeObject>)bin.Deserialize(stream);Line however i do not know why.
You need to remove the static from your properties
[Serializable]
public class FileSerializeObject
{
public string FileName { get; set; }
public string Extension { get; set; }
public string Base64 { get; set; }
public FileSerializeObject(string filename, string extension, string base64vaulue)
{
FileName = filename;
Extension = extension;
Base64 = base64vaulue;
}
}
Try to set the [Serializable()] attribute for each property.
So it would look like this:
[Serializable()]
public class FileSerilizeObject
{
[Serializable()]
public string FileName { get; set; }
[Serializable()]
public string Extension { get; set; }
[Serializable()]
public string Base64 { get; set; }
public FileSerilizeObject(string filename, string extension, string base64vaulue)
{
FileName = filename;
Extension = extension;
Base64 = base64vaulue;
}
}
}
EDIT: Removed static keyword from properties.
I tested your code into a console application and it is working for me, I tested with VS 2013 but I used the same code that you wrote above.
Some details:
1. I removed the word static form the "FileSerilizeObject"
The class FileSerilizeObject
[Serializable()]
public class FileSerilizeObject
{
public string FileName { get; set; }
public string Extension { get; set; }
public string Base64 { get; set; }
public FileSerilizeObject(string filename, string extension, string base64vaulue)
{
FileName = filename;
Extension = extension;
Base64 = base64vaulue;
}
}
Functions
public static void Serialize(List<FileSerilizeObject> List)
{
using (Stream stream = File.Open(#"C:\Users\ttest\Desktop\folder1\data.bin", FileMode.OpenOrCreate))
{
BinaryFormatter bin = new BinaryFormatter();
bin.Serialize(stream, List);
stream.Close();
}
}
public static List<FileSerilizeObject> Deserialised(string OpenPath)
{
List<FileSerilizeObject> defo;
using (Stream stream = File.Open(OpenPath, FileMode.Open))
{
BinaryFormatter bin = new BinaryFormatter();
defo = (List<FileSerilizeObject>)bin.Deserialize(stream);
}
return defo;
}
Main
var bytes = Encoding.UTF8.GetBytes("dffesdbcdef==");
var base64 = Convert.ToBase64String(bytes);
FileSerilizeObject f1 = new FileSerilizeObject("test", "jpg", base64);
bytes = Encoding.UTF8.GetBytes("ggasddbcdef==");
base64 = Convert.ToBase64String(bytes);
FileSerilizeObject f2 = new FileSerilizeObject("test2", "png", base64);
bytes = Encoding.UTF8.GetBytes("asddffasdasdasdesdbcdef==");
base64 = Convert.ToBase64String(bytes);
FileSerilizeObject f3 = new FileSerilizeObject("test3", "doc", base64);
List<FileSerilizeObject> lFiles = new List<FileSerilizeObject>();
lFiles.Add(f1);
lFiles.Add(f2);
lFiles.Add(f3);
Serialize(lFiles);
Deserialised(#"C:\Users\rjimen4x\Desktop\tutoriales\data.bin");

protobuf does not deserialize object corrctly

I have three classes:
[ProtoContract]
public class Message
{
[ProtoMember(1)]
public int MethodId { set; get; }
[ProtoMember(2)]
public CustomArgs Arguments { set; get; }
}
[ProtoContract]
public class CustomArgs
{
[ProtoMember(1)]
public int IntVal { set; get; }
[ProtoMember(2)]
public string StrVal { set; get; }
[ProtoMember(3)]
public CycleData Cd { set; get; }
}
[ProtoContract]
public class CycleData
{
[ProtoMember(1)]
public int Id { set; get; }
[ProtoMember(2, AsReference = true)]
public CycleData Owner { set; get; }}
So when I create objects then serialize and deserialize it the Arguments property stay null but orignal object have a value. The sample code is:
static void Main(string[] args)
{
CycleData cd = new CycleData()
{
Id = 5
};
cd.Owner = cd;
CustomArgs a = new CustomArgs()
{
IntVal = 5,
StrVal = "string",
Cd = cd
};
Message oldMsg = new Message()
{
MethodId = 3,
Arguments = a
};
Stream st = new MemoryStream();
ProtoBuf.Serializer.Serialize(st, oldMsg);
var newMsg = ProtoBuf.Serializer.Deserialize<Message>(st);
}
So newMsg.Arguments is null after deserialize. What i do wrong?
You have a simple error. Once you serialize/write to the memstream, the .Pointer remain at the end of the stream. Deserializing immediately after using on the same stream fails because there is nothing to read after that point. Just reset it:
using (Stream st = new MemoryStream())
{
ProtoBuf.Serializer.Serialize(st, oldMsg);
st.Position = 0; // point to start of stream
var newMsg = ProtoBuf.Serializer.Deserialize<Message>(st);
}
I also put the stream in a using block to dispose of it.

Derived Class Deserialization

I have a problem with deserialization with my logic simulation program.
Here are my element classes:
public class AndGateData : TwoInputGateData
{
}
public class TwoInputGateData : GateData
{
public TwoInputGateData()
{
Input2 = new InputData();
Input1 = new InputData();
}
public InputData Input1 { get; set; }
public InputData Input2 { get; set; }
}
public class GateData : ElementData
{
public GateData()
{
OutputData = new OutputData();
}
public OutputData OutputData { get; set; }
}
public class ElementData
{
public int Delay { get; set; }
public Guid Id { get; set; }
}
And here are classes responsible for sockets:
public class InputData : SocketData
{
}
public class SocketData
{
public Guid Id { get; set; }
public SignalData SignalData { get; set; }
}
SignalData is not important here. So, I won't write it (in order to keep this question clean) here unless somebody says it is necessary.
CircuitData is very important:
[XmlRoot("Circuit")]
public class CircuitData
{
[XmlElement(typeof(AndGateData))]
[XmlElement(typeof(OrGateData))]
public List<ElementData> elements = new List<ElementData>();
public List<WireData> wires = new List<WireData>();
public void AddElement(ElementData element)
{
elements.Add(element);
}
public void AddWire(WireData wire)
{
wires.Add(wire);
}
}
Wires are not important right now.
Now, I have written some Serialization:
public class CircuitDataWriter
{
public static void Write(object obj, string fileName)
{
var xmlFormat = new XmlSerializer(typeof(CircuitData));
using(Stream fStream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None) )
{
xmlFormat.Serialize(fStream,obj);
}
Console.WriteLine("Circuit saved in XML format.");
}
}
It works just like I wanted, it produces that xml document:
<?xml version="1.0"?>
-<Circuit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
-<AndGateData>
<Delay>10</Delay>
<Id>bfee6dd7-5946-4b7b-9d0b-15d5cf60e2bf</Id>
-<OutputData> <Id>00000000-0000-0000-0000-000000000000</Id> </OutputData>
-<Input1> <Id>7c767caf-79a9-4c94-9e39-5c38ec946d1a</Id> <SignalData xsi:type="SignalDataOn"/> </Input1>
-<Input2> <Id>d2cad8f8-8528-4db3-9534-9baadb6a2a14</Id> <SignalData xsi:type="SignalDataOff"/> </Input2>
</AndGateData>
<wires/>
</Circuit>
But I have problem with my DESERIALIZATION. Here is the code:
public static CircuitData Read()
{
var reader = new XmlSerializer(typeof(CircuitData));
StreamReader file = new StreamReader("Circuit.xml");
var returnCircuitData = new CircuitData();
returnCircuitData = (CircuitData) reader.Deserialize(file);
return returnCircuitData;
}
Now, it deserializes my Circuit.xml to object, but this object only contains Id and Delay, it does not contain Input1, Input2 or Output. So, it is treated like Element, not like AndGate. I tried to solve it out for a day but it seems that no one has that kind of problem.
I have a suggestion for you, make the Write method generic like this and create the serializer using objectToSerialize.GetType():
public static void Write<T>(T objectToSerialize, string fileName)
{
var xmlSerializer = new XmlSerializer(objectToSerialize.GetType());
...
}
The XmlSerializer.Deserialize() method returns object, you can make your Read method generic like this:
public static T Read<T>(string fileName)
{
var serializer = new XmlSerializer(typeof(T));
using (StreamReader file = new StreamReader(fileName))
{
return (T)serializer.Deserialize(file);
}
}
Other than that you might want to read about:
XmlInclude that is used when you serialize derived classes.
XmlArray and XmlArrayItem that are used for controlling serialization of arrays

Categories

Resources