Reading serialized objects from binary file - c#

I'm trying to write and read serialized objects to a binary file. I'm using Append FileMode to add serialized objects but when i try to read the file, it only print a single deserialized object.
Here's my serialization method.
public void serialize(){
MyObject obj = new MyObject();
obj.n1 = 1;
obj.n2 = 24;
obj.str = "Some String";
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream("MyFile.bin", FileMode.Append, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, obj);
stream.Close()
}
Here's my deserialization method.
public static void read()
{
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream("MyFile.bin", FileMode.Open, FileAccess.Read, FileShare.Read);
MyObject obj = (MyObject)formatter.Deserialize(stream);
stream.Close();
// Here's the proof.
Console.WriteLine("n1: {0}", obj.n1);
Console.WriteLine("n2: {0}", obj.n2);
Console.WriteLine("str: {0}", obj.str);
}
How can we loop through every single serialized record in file, like we use File.eof() or while(file.read()) in C++.

Deserialize only returns one object. You need to create a collection and loop until the end of the stream is reached:
List<MyObject> list = new List<MyObject>();
Stream stream = new FileStream("MyFile.bin", FileMode.Open, FileAccess.Read, FileShare.Read);
while(stream.Position < stream.Length)
{
MyObject obj = (MyObject)formatter.Deserialize(stream);
list.add(obj);
}

The explanation above is correct, however I'd put it like this, using a collection of your like:
public static void serializeIt()
{
MyObject obj = new MyObject();
obj.n1 = 1;
obj.n2 = 24;
obj.str = "Some String";
MyObject obj2 = new MyObject();
obj2.n1 = 1;
obj2.n2 = 24;
obj2.str = "Some other String";
List<MyObject> list = new List<MyObject>();
list.Add(obj);
list.Add(obj2);
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream("MyFile.bin", FileMode.Append,FileAccess.Write, FileShare.None);
formatter.Serialize(stream, list);
stream.Close();
}
public static void read()
{
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream("MyFile.bin", FileMode.Open, FileAccess.Read, FileShare.Read);
List<MyObject> list = (List<MyObject>)formatter.Deserialize(stream);
stream.Close();
}
You should also make sure that the MyFile.bin is rewriten each time you serialize your collection, as it would always return the collection that was saved first if you'd keep appending them. That should be the only downside.

Thank you for your help, I made this.
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
private static Dictionary<int, ArrayList> J1_CarteDeck;
private static string PathDocuments = String.Format("{0}\\Antize Game\\", Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));
private const string FILE_NAME = "Antize.data";
public static bool SauvegarderDeck()
{
if (!(Directory.Exists(PathDocuments)))
Directory.CreateDirectory(PathDocuments);
if (File.Exists(PathDocuments + FILE_Deck))
File.Delete(PathDocuments + FILE_Deck);
foreach (ArrayList child in J1_CarteDeck.Values)
{
if(child != null)
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = new FileStream(PathDocuments + FILE_Deck, FileMode.Append, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, child);
stream.Close();
}
}
if (File.Exists(PathDocuments + FILE_Deck))
return true;
else
return false;
}
public static bool ChargerDeck()
{
if (!(File.Exists(PathDocuments + FILE_Deck)))
return false;
int cptr = 1;
J1_CarteDeck = new Dictionary<int, ArrayList>();
BinaryFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream(PathDocuments + FILE_Deck, FileMode.Open, FileAccess.Read, FileShare.None);
while (stream.Position < stream.Length)
{
J1_CarteDeck[cptr] = (ArrayList)formatter.Deserialize(stream);
cptr++;
}
stream.Close();
return true;
}

Simply iterate through each object in binary file
using (System.IO.FileStream fs = new System.IO.FileStream("D:\\text\\studentdata.txt", System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter sf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
Object o = sf.Deserialize(fs);
while (fs.Position < fs.Length)
{
o = sf.Deserialize(fs);
Student student = (o as Student);
Console.WriteLine("str: {0}", student.sname);
}
}

Related

How to read binary files until EOF in C#

I have a function to write some data into a binary file
private void writeToBinFile (List<MyClass> myObjList, string filePath)
{
FileStream fs = new FileStream(filePath, FileMode.Create);
BinaryWriter bw = new BinaryWriter(fs);
foreach (MyClass myObj in myObjList)
{
bw.Write(JsonConvert.SerializeObject(myObj));
}
bw.Close();
fs.Close();
}
I am looking something like
FileStream fs = new FileStream(filePath, FileMode.Create);
BinaryReader bw = new BinaryReader(fs);
while (!filePath.EOF)
{
List<MyClass> myObjList = br.Read(myFile);
}
anyone can help with this?
thanks in advance
JSON can be saved with no formatting (no new lines), so you can save 1 record per row of a file. Thus, my suggested solution is to ignore binary files and instead use a regular StreamWriter:
private void WriteToFile(List<MyClass> myObjList, string filePath)
{
using (StreamWriter sw = File.CreateText(filePath))
{
foreach (MyClass myObj in myObjList)
{
sw.Write(JsonConvert.SerializeObject(myObj, Newtonsoft.Json.Formatting.None));
}
}
}
private List<MyClass> ReadFromFile(string filePath)
{
List<MyClass> myObjList = new List<MyClass>();
using (StreamReader sr = File.OpenText(filePath))
{
string line = null;
while ((line = sr.ReadLine()) != null)
{
myObjList.Add(JsonConvert.DeserializeObject<MyClass>(line));
}
}
return myObjList;
}
If you really want to use the binary writer to save JSON, you could change it to be like this:
private void WriteToBinFile(List<MyClass> myObjList, string filePath)
{
using (FileStream fs = new FileStream(filePath, FileMode.Create))
using (BinaryWriter bw = new BinaryWriter(fs))
{
foreach (MyClass myObj in myObjList)
{
bw.Write(JsonConvert.SerializeObject(myObj));
}
}
}
private List<MyClass> ReadFromBinFile(string filePath)
{
List<MyClass> myObjList = new List<MyClass>();
using (FileStream fs = new FileStream(filePath, FileAccess.Read))
using (BinaryReader br = new BinaryReader(fs))
{
while (fs.Length != fs.Position) // This will throw an exception for non-seekable streams (stream.CanSeek == false), but filestreams are seekable so it's OK here
{
myObjList.Add(JsonConvert.DeserializeObject<MyClass>(br.ReadString()));
}
}
return myObjList;
}
Notes:
I've added using around your stream instantiations so that the files are properly closed when memory is freed
To check the stream is at the end, you have to compare Length to Position.

C# Binaryformatter deserialize to string?

I am serializing only one data to MyFile.bin file, now i have to deserialize it to a string or Int and add +1 with current value and save it again, In order to do this how to deserialize the value to Int or String variable?
Code
public void saveMember()
{
string pathMemberPk = Path.Combine(Environment.CurrentDirectory, #"../memberDataPk.bin");
if (!File.Exists(pathMemberPk)) {
memberPk = 0001;
memberPkString = memberPk.ToString();
IFormatter formatter = new BinaryFormatter();
Stream streamPk = new FileStream(pathMemberPk, FileMode.Create);
formatter.Serialize(streamPk,this.memberPkString);
}else{
using (FileStream streamIn = File.OpenRead("f://MyFile.bin"))
{
string pk;
BinaryFormatter formatter = new BinaryFormatter();
string pkk = (pk)formatter.Deserialize(streamIn).ToString();
}
}
}
I Solved Myself
public void saveMember()
{
string pathMemberPk = Path.Combine(Environment.CurrentDirectory, #"../memberDataPk.bin");
if (!File.Exists(pathMemberPk)) {
memberPk = 0001;
memberPkString = memberPk.ToString();
IFormatter formatter = new BinaryFormatter();
Stream streamPk = new FileStream(pathMemberPk, FileMode.Create);
formatter.Serialize(streamPk,this.memberPkString);
}else{
using (FileStream streamIn = File.OpenRead("f://MyFile.bin"))
{
IFormatter formatter = new BinaryFormatter();
object obj = formatter.Deserialize(streamIn);
memberPk = Convert.ToInt32(obj); //to INT
memberPk = Convert.ToString(obj); //To String
Console.WriteLine(memberPk);
}
}
}

binary serialization to list

I used this information to convert a list to .txt with binary serialization. now I want to load that file, and put it again in my list.
this is my code to convert a list to .txt with binary serialization:
public void Save(string fileName)
{
FileStream fs = new FileStream(#"C:\" + fileName + ".txt", FileMode.Create);
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(fs, list);
fs.Close();
}
so my question is; how to convert this binary file back to a list?
You can do it like this:
//Serialize: pass your object to this method to serialize it
public static void Serialize(object value, string path)
{
BinaryFormatter formatter = new BinaryFormatter();
using (Stream fStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None))
{
formatter.Serialize(fStream, value);
}
}
//Deserialize: Here is what you are looking for
public static object Deserialize(string path)
{
if (!System.IO.File.Exists(path)) { throw new NotImplementedException(); }
BinaryFormatter formatter = new BinaryFormatter();
using (Stream fStream = File.OpenRead(path))
{
return formatter.Deserialize(fStream);
}
}
Then use these methods:
string path = #"C:\" + fileName + ".txt";
Serialize(list, path);
var deserializedList = Deserialize(path);
Thanks #Hossein Narimani Rad , I used your answer and changed it a bit (so I understand it more) and now it works.
my binair serialize method (save) is still the same.
this is my binair deserialize method (load):
public void Load(string fileName)
{
FileStream fs2 = new FileStream(fileName, FileMode.Open);
BinaryFormatter binformat = new BinaryFormatter();
if (fs2.Length == 0)
{
MessageBox.Show("List is empty");
}
else
{
LoadedList = (List<Object>)binformat.Deserialize(fs2);
fs2.Close();
List.Clear();
MessageBox.Show(Convert.ToString(LoadedList));
List.AddRange(LoadedList);
}
I know I don't have an exception now, but I understand it better this way.
I also added some code to fill my listbox with my List with the new LoadedList.

Deserialization of MemoryStream via BinaryFormatter

didn't find a solution to following problem.
I had a working code for saving/loading a TreeView in a file but I want to save it to Properties.Settings.Default.
Unfortunately I get the error "no map for object" in this line:
object obj = bf.Deserialize(ms);
Here is the complete code for (de)serialization:
Don't know how to solve this one. :(
public static void SaveTreeView(TreeView tree)
{
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, tree.Nodes.Cast<TreeNode>().ToList());
ms.Position = 0;
var sr = new StreamReader(ms);
Properties.Settings.Default.tree = sr.ReadToEnd();
Properties.Settings.Default.Save();
}
}
public static void LoadTreeView(TreeView tree)
{
using (MemoryStream ms = new MemoryStream())
{
var sw = new StreamWriter(ms);
sw.WriteLine(Properties.Settings.Default.tree);
sw.Flush();
ms.Seek(0, SeekOrigin.Begin);
BinaryFormatter bf = new BinaryFormatter();
object obj = bf.Deserialize(ms);
TreeNode[] nodeList = (obj as IEnumerable<TreeNode>).ToArray();
tree.Nodes.AddRange(nodeList);
}
}
Anybody got an idea?
Thanks is advance.
Try this out
public static void SaveTree(TreeView tree)
{
using (var ms = new MemoryStream())
{
new BinaryFormatter().Serialize(ms, tree.Nodes.Cast<TreeNode>().ToList());
Properties.Settings.Default.tree = Convert.ToBase64String(ms.ToArray());
Properties.Settings.Default.Save();
}
}
public static void LoadTree(TreeView tree)
{
byte[] bytes = Convert.FromBase64String(Properties.Settings.Default.tree);
using (var ms = new MemoryStream(bytes, 0, bytes.Length))
{
ms.Write(bytes, 0, bytes.Length);
ms.Position = 0;
var data = new BinaryFormatter().Deserialize(ms);
tree.Nodes.AddRange(((List<TreeNode>)data).ToArray());
}
}

"Binary stream does not contain a valid BinaryHeader" error on (de)serialization?

I am created a post before " Object to byte not working " .
I fixed problems that users said me , but there is still problem .
Error Message : The constructor to deserialize an object of type 'WindowsFormsApplication1.Form1+Item' was not found.;
void start()
{
Item item = new Item();
item.files.Add(#"test");
byte[] b = ObjectToByteArray(item);
Item k = Desriles(b);
}
[Serializable]
public class Item : ISerializable
{
public Item()
{
files = new List<string>();
Exclude = false;
CleanEmptyFolder = false;
}
public List<string> files;
public string MusicProfileName;
public bool Exclude;
#region ISerializable Members
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("files", files);
info.AddValue("MusicProfileName", MusicProfileName);
info.AddValue("Exclude", Exclude);
}
#endregion
}
public byte[] ObjectToByteArray(object _Object)
{
using (var stream = new MemoryStream())
{
// serialize object
var formatter = new BinaryFormatter();
formatter.Serialize(stream, _Object);
// get a byte array
var bytes = new byte[stream.Length];
using (BinaryReader br = new BinaryReader(stream))
{
bytes = br.ReadBytes(Convert.ToInt32(stream.Length));
}
return bytes;
}
}
public Item Desriles(byte[] items)
{
using (MemoryStream stream = new MemoryStream())
{
stream.SetLength(items.LongLength);
stream.write(items, 0, items.Length);
var formatter = new BinaryFormatter();
stream.Seek(0, SeekOrigin.Begin);
object item = formatter.Deserialize(stream); // Here I will get error
return (Item)item;
}
}
The serialization code can't work properly, you forgot to reset the stream back to the beginning. The better mouse trap:
public byte[] ObjectToByteArray(object _Object) {
using (var stream = new MemoryStream()) {
var formatter = new BinaryFormatter();
formatter.Serialize(stream, _Object);
return stream.ToArray();
}
}
The deserialization code can similarly be simplified:
public Item Desriles(byte[] items) {
using (MemoryStream stream = new MemoryStream(items)) {
var formatter = new BinaryFormatter();
return (Item)formatter.Deserialize(stream);
}
}
And you don't need GetObjectData().
In this section:
using (MemoryStream stream = new MemoryStream())
{
stream.SetLength(items.LongLength);
stream.Read(items, 0, items.Length);
[...]
object item = formatter.Deserialize(stream);
it seems you are creating a new, empty memory stream, then attempting to read from it, and Deserialize from it.
Of course it fails. The stream is empty.
abelenky makes a good point, but I don't think your:
public byte[] ObjectToByteArray(object _Object)
works either.
C# Code Snippet - Object to byte array
C# Code Snippet - Byte array to object
Thanks to All :
I found problem : I should base that to ISerializable

Categories

Resources