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.
Related
I want to run a program that saves object by serializing it to a bin file.
The problem is, when I serialize one object to a new file, I can't add to the same file same object without erasing it.
Is there any method to serialize objects with the same type one by one, and then deserialized a list of the object?
this is the object saving:
static void Main(string[] args)
{
UserHandler.saveUser("or kandabi", "2133", "board 1");
UserHandler.saveUser("dana waizer", "21343", "board 2");
UserHandler.saveUser("elad", "4353", "board 3");
}
this is the methods for saving the object
public static void saveUser(String userName,String password,String boardId)
{
DalUser u = new DalUser(userName, password, boardId);
if (!File.Exists("userData.bin"))
{
Stream myFileStream = File.Create("userData.bin");
BinaryFormatter serializes = new BinaryFormatter();
serializes.Serialize(myFileStream, u);
myFileStream.Close();
}
else
{
Stream myFileStream = File.OpenRead("userData.bin");
BinaryFormatter serializes = new BinaryFormatter();
serializes.Serialize(myFileStream, u);
myFileStream.Close();
}
}
I expected that the data whould saved in the same "userData.bin" file, but there was an exception that the stream could not be opened for writing.
Use FileStream and FileMode.Append. Then you are able to add any object to your file and later you can read them as a list. Change your code to the following:
public static void saveUser(String userName, String password, String boardId)
{
DalUser u = new DalUser(userName, password, boardId);
using (var fileStream = new FileStream("userData.bin", FileMode.Append))
{
var bFormatter = new BinaryFormatter();
bFormatter.Serialize(fileStream, u);
}
}
public static List<DalUser> readUsers()
{
if (!File.Exists("userData.bin"))
return null;
var list = new List<DalUser>();
using (var fileStream = new FileStream("userData.bin", FileMode.Open))
{
var bFormatter = new BinaryFormatter();
while (fileStream.Position != fileStream.Length)
{
list.Add((DalUser)bFormatter.Deserialize(fileStream));
}
}
return list;
}
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.
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);
}
}
I am working on a list program that contains a 2-column listbox. Both columns contain strings that I wish to save as a file. The file format doesn't really matter as long as it can be read and populate the listbox again at startup.
Any help will be extremely appreciated!
You could populate your list box from a custom object and serialize that object to disk:
using System;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Windows.Forms;
//Serialize an object to disk (properties must be public):
public string Serialize(Object Input, string OutFile)
{
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();
XmlSerializer XML = new XmlSerializer(Input.GetType());
XML.Serialize(memoryStream, Input);
memoryStream.Flush();
memoryStream.Position = 0;
if (!string.IsNullOrEmpty(OutFile))
{
using (FileStream fileStream = new FileStream(OutFile, FileMode.Create))
{
byte[] data = memoryStream.ToArray();
fileStream.Write(data, 0, data.Length);
fileStream.Close();
}
}
return new System.IO.StreamReader(memoryStream).ReadToEnd();
}
//Deserialize from a serialized file:
public object DeserializeFile(Type ObjectType, string FileName)
{
Type type = typeof(object);
if (ObjectType != null)
{ type = ObjectType; }
using (FileStream fileStream = new FileStream(FileName, FileMode.Open, FileAccess.Read))
{
StreamReader sr = new StreamReader(fileStream);
string XML = sr.ReadToEnd();
XmlSerializer xmlSerializer = new System.Xml.Serialization.XmlSerializer(type);
fileStream.Close();
return xmlSerializer.Deserialize(new StringReader(XML));
}
}
CustomObject co = DeserializeFile(typeof(CustomObject), fileName.xml) as CustomObject;
I use this method to save the contents of a CheckedListBoxControl to disk so users are able to define it with their own items.
First off, the display of your data and what gui widgets you use is completely irrelevant (i.e. that you are using a "2 column listbox" doesn't matter). What is relevant (in this case of a listbox) is the collection of objects that is bound to your listbox.
The collection class is really the important element here for the purposes of loading & saving. Its contents are what you will be saving and loading from your file. The listbox that displays the data doesn't care; it simply displays the data of the collection it is bound to using whatever template you've setup.
So how do you load & save you ask? Here's a simple example that uses binary formatting. There are a gazillion other walkthrus on the Intertubes; just google "C# Serialization to file"
public void Serialize(string filename, ObjectToSerialize objectToSerialize)
{
Stream stream = File.Open(filename, FileMode.Create);
BinaryFormatter bFormatter = new BinaryFormatter();
bFormatter.Serialize(stream, objectToSerialize);
stream.Close();
}
public ObjectToSerialize DeSerialize(string filename)
{
ObjectToSerialize objectToSerialize;
Stream stream = File.Open(filename, FileMode.Open);
BinaryFormatter bFormatter = new BinaryFormatter();
objectToSerialize = (ObjectToSerialize)bFormatter.Deserialize(stream);
stream.Close();
return objectToSerialize;
}
Look into the StreamReader and StreamWriter classes.
For saving the listbox contents:
using (StreamWriter tWrite = new StreamWriter(#"c:\temp\test.txt"))
{
foreach (string tItem in listBox1.Items)
{
tWrite.WriteLine(tItem);
}
}
For reading file contents:
listBox1.Items.AddRange(File.ReadAllLines(#"c:\temp\test.txt"));
I'm trying to do custom serialization/deserialization of an object as well as compressing/decompressing the serialized data with DeflateStreams. I originally did this for more complex objects but cut it down to try and figure out the problem, however it just became more puzzling as it is still there. Here is the class to be serialized/deserialized:
[Serializable]
public class RandomObject : ISerializable
{
public String Name { get; set; }
public String SavePath { get; set; }
public RandomObject()
{
}
public RandomObject(String name, String savepath)
{
Name = name;
SavePath = savepath;
}
public RandomObject(SerializationInfo info, StreamingContext context)
: this(info.GetString("name"), info.GetString("savepath"))
{
}
[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("name", Name);
info.AddValue("savepath", SavePath);
}
}
And here is the code that is supposed to serialize it(which seems to work):
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
bf.Serialize(ms, profile);
using (DeflateStream ds = new DeflateStream(ms, CompressionMode.Compress))
{
try
{
using (FileStream fs = File.Create(path))
{
ds.Flush();
Miscellaneous.CopyStream(ds.BaseStream, fs);
fs.Flush();
fs.Close();
}
}
catch (IOException e)
{
MessageBox.Show(e.Message);
success = false;
}
ds.Close();
}
ms.Close();
}
And here is the deserialization:
RandomObject profile = null;
using (FileStream fs = File.OpenRead(path))
{
using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Decompress))
{
BinaryFormatter bf = new BinaryFormatter();
ds.Flush();
using (MemoryStream ms = new MemoryStream())
{
Miscellaneous.CopyStream(ds.BaseStream, ms);
profile = bf.Deserialize(ms) as RandomObject;
profile.SavePath = path;
ms.Close();
}
ds.Close();
}
fs.Close();
}
Now, to the problem. Deserialization throws a SerializationException with the message {"No map for object '201326592'."} I have no idea how to troubleshoot or figure out what exactly is causing the problem. Very basic serialization works when I just run BinaryFormatter's Serialize and Deserialize methods on the same MemoryStream.
I tried removing the DeflateStream stuff from both methods, but it's still the same problem. When I look at the examples at MSDN and other places it looks like I'm doing it just right, and googling for the exception message doesn't give any meaningful results(or perhaps I'm just bad at searching).
PS. As you can see I use Miscellaneous.CopyStream(src, dest) which is a basic stream copier, as I can't get src.CopyTo(dest) to work at all, so any hints on that is welcome as well.
Below is a link to the whole VS2010 project if you would like to look at it more closely:
http://www.diredumplings.com/SerializationTesting.zip
UPDATE:
The_Smallest: I tried using the Compress method you posted on my serialization:
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream stream = new MemoryStream())
{
bf.Serialize(stream, profile);
byte[] array = Compress(stream);
using (MemoryStream ms = new MemoryStream(array))
{
using (FileStream fs = File.Create(path))
{
ms.WriteTo(fs);
fs.Flush();
}
}
}
However, it seems to give me the same problems that I had with srcStream.CopyTo(destStream) earlier, which is that it doesn't seem to get written to the stream. The result is a 0 kb file when I try to save it to disk. Any ideas?
Pieter: I removed the MemoryStream from the deserialization method and it seems have the same functionality as before. However I'm not sure how to implement the serialization the way you suggested. Is this what you had in mind?
BinaryFormatter bf = new BinaryFormatter();
using (FileStream fs = File.Create(path))
{
using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Compress))
{
bf.Serialize(ds, profile);
fs.Flush();
ds.Close();
}
fs.Close();
}
Thanks to both of you!
I dowloaded you example and digged a little in there. See changes for your project below:
Replace LoadFromFile in Loader.cs
private static RandomObject LoadFromFile(string path)
{
try
{
var bf = new BinaryFormatter();
using (var fileStream = File.OpenRead(path))
using (var decompressed = new MemoryStream())
{
using (var deflateStream = new DeflateStream(fileStream, CompressionMode.Decompress))
deflateStream.CopyTo(decompressed);
decompressed.Seek(0, SeekOrigin.Begin);
var profile = (RandomObject)bf.Deserialize(decompressed);
profile.SavePath = path;
return profile;
}
}
catch (IOException e)
{
MessageBox.Show(e.Message);
return null;
}
}
Replace Save in Saver.cs as follows:
public static bool Save(RandomObject profile, String path)
{
try
{
var bf = new BinaryFormatter();
using (var uncompressed = new MemoryStream())
using (var fileStream = File.Create(path))
{
bf.Serialize(uncompressed, profile);
uncompressed.Seek(0, SeekOrigin.Begin);
using (var deflateStream = new DeflateStream(fileStream, CompressionMode.Compress))
uncompressed.CopyTo(deflateStream);
}
return true;
}
catch (IOException e)
{
MessageBox.Show(e.Message);
return false;
}
}
You should serialize into the DeflateStream, not the base (MemoryStream) stream.
For serializing: begin with the File.Create. Then around that stream, create the DeflateStream. Then to the DefaulteStream, serialize your objects.
For deserializing: do not create the MemoryStream and deserialize directly from the DeflateStream.
I believe there is no need for the added MemoryStream. If however you do have problems writing directly to/reading directly from the file streams, just change the serialize routine to write to the DeflateStream instead of the MemoryStream.
That should solve your issues.
There is error in streams logics, while compressing you should write to CompressStream, which writes to MemoryStream, after this you will have result in MemoryStream (not in CompressStream)
Here is example how to compress and decompress bytes
private static byte[] Compress(Stream stream)
{
using (var resultStream = new MemoryStream())
{
using (var gzipStream = new DeflateStream(resultStream, CompressionMode.Compress))
stream.CopyTo(gzipStream);
return resultStream.ToArray();
}
}
private static byte[] Decompress(byte[] bytes)
{
using (var readStream = new MemoryStream(bytes))
using (var resultStream = new MemoryStream())
{
using (var gzipStream = new DeflateStream(readStream, CompressionMode.Decompress))
gzipStream.CopyTo(resultStream);
return resultStream.ToArray();
}
}