public static List<Restaurant> LoadRestaurantList()
{
FileStream fs = new FileStream("Restaurant.txt", FileMode.OpenOrCreate);
BinaryFormatter bf = new BinaryFormatter();
List<Restaurant> rest =(List<Restaurant>)bf.Deserialize(fs);
fs.Close();
return rest;
}
I have Serailze the generic list which I have, into "Restaurant.txt" file.
now I want to Deserialize the same and return it into a Generic List, I have tried
but its not working and it is giving error "Invalid Cast Expression".
This is the Serialization code:
public static void SaveRestaurantList(List<Restaurant> restaurantList)
{
FileStream fs = new FileStream("Restaurant.txt", FileMode.Create, FileAccess.Write);
BinaryFormatter bf = new BinaryFormatter();
for (int i = 0; i < restaurantList.Count; i++)
{
Restaurant r = new Restaurant();
r = (Restaurant)restaurantList[i];
bf.Serialize(fs, r);
fs.Flush();
}
fs.Close();
}
Can anyone please help in solving out this.
Serialization and Deserialization are each others opposites. This means the type(s) used during serialization needs to be the same during deserialization.
In your code that is not the case. You serialize Restaurant types but when you deserialize you expect a List.
Adapt your serialization code as follows:
public static void SaveRestaurantList(List<Restaurant> restaurantList)
{
using(FileStream fs = new FileStream("Restaurant.txt", FileMode.Create, FileAccess.Write))
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(fs, restaurantList);
}
}
Related
I am using Binary Formatter to save/load data from a file. I have a library system, with two concrete classes - Users and Items - and an abstract class - Library. I am also using two lists:
List<Item> items = new List<Item>();
List<User> users = new List<User>();
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);
}
}
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);
}
}
}
Above are the two methods that I'm using to save and load.
To call them from the Program file, I am using this code for saving:
string pathItem1 = #"itemList";
string pathUser1 = #"userList";
Library.Serialize(Library.myItems, pathItem1);
Library.Serialize(Library.myUsers, pathUser1);
Console.WriteLine("Serializing...");
and this code for loading:
string pathItem = #"itemList";
string pathUser = #"userList";
//var deserializedItem
List<Item> items= (List<Item>)Library.Deserialize(pathItem);
//var deserializedUser =
List<User> users = (List<User>)Library.Deserialize(pathUser);
Console.WriteLine("Deserializing...");
Saving seems to work fine. Loading however isn't. I am getting this error message:
Additional information: Unable to cast object of type 'System.Collections.Generic.List1[LibrarySystem.User]' to type 'System.Collections.Generic.List1[LibrarySystem.Item]'.
Thanks!
You have a strange code in your Serialize method. You are saving value parameter to both pathes: "itemList" and "userList". And actually you are not using path parameter. Your code should looks like this:
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);
}
}
With this implementation your code will work as expected.
public static void Serialize(object value, string path)
{
BinaryFormatter formatter = new BinaryFormatter();
using (Stream fStream = new FileStream(#"itemList", FileMode.Create, FileAccess.Write, FileShare.None))
{
formatter.Serialize(fStream, value);
}
using (Stream fStream = new FileStream(#"userList", FileMode.Create, FileAccess.Write, FileShare.None))
{
formatter.Serialize(fStream, value);
}
}
You're storing value in both userList and itemList, despite passing the path as a parameter. And since the last call is Library.Serialize(Library.myUsers, pathUser1), what's in itemList is a list of User objects -- exactly what the error is telling you.
The fix is obvious, simply use the passed path, however you should consider a more robust state storing system. For example you can have a class that contains both lists and you serialize that.
And skipping over a few relatively obvious improvements (Deserialize is a prime candidate for a generic function so you don't have to cast it every time for example), one important note is that NotImplementedException isn't something vague you can tack your own meaning to, it has a very precise meaning in the context of the .Net framework, and that's a function in your code that you didn't implement for various reasons. The "generic" exception you want is either ArgumentException or InvalidOperationException.
I've got a List of Types that I need to save to file and read it after.
I use DataContractSerializer but I get an exception during deserialization:
Can't find constructor with arguments (SerializationInfo,
StreamingContext) in ISerializable "System.RuntimeType".
I've added System.RuntimeType as a known type to my serializer, but it didn't help.
Here's code of my two methods
public static void SaveTypes(List<Type> types, string fileName)
{
Type rt = types[0].GetType();
List<Type> knownTypes = new List<Type>() { rt }; //I get a List with System.RuntimeType item here
DataContractSerializer serializer = new DataContractSerializer(typeof(List<Type>), knownTypes);
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
Stream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);
using (XmlWriter xw = XmlWriter.Create(fs, settings))
serializer.WriteObject(xw, types);
}
Serialization seems to work fine, and the output file is ok, but problem starts on deserializing:
public static object LoadTypes(string fileName)
{
Stream file = new FileStream(fileName, FileMode.Open, FileAccess.Read);
byte[] data = new byte[file.Length];
file.Read(data, 0, (int)file.Length);
Type rt = file.GetType();
List<Type> knownTypes = new List<Type>() { rt.GetType() };
DataContractSerializer deserializer = new DataContractSerializer(typeof(List<Type>), knownTypes);
Stream stream = new MemoryStream();
stream.Write(data, 0, data.Length);
stream.Position = 0;
return deserializer.ReadObject(stream); //exception here
}
Is there any way to go through this? Or maybe there's some other way to store types?
Marc Gravell is right, you probably should be serializing the data and not the types.
But for some reason, if you really want to serialize the types themselves, then you shouldn't serialize the Type object (pretty sure it's not serailizable). Anyway, serialize Type.FullName instead. When you load the Types, use Type.Load
public static void SaveTypes(IEnumerable<Type> types, string filename)
{
using (var fs = File.Open(filename, FileMode.OpenOrCreate)
new XmlSerializer(typeof(string[]))
.Serialize(fs, types.Select(t => t.FullName).ToArray())
}
public static IEnumerable<Type> LoadTypes(string filename)
{
using (var fs = File.Open(filename, FileMode.Open)
{
var typeNames = (string[])
new XmlSerializer(typeof(string[]))
.Deserialize(fs);
return typeNames.Select(t => Type.Load(t));
}
}
Note: When working with any Stream (or really any IDisposable) you have to either call the Dispose method or use the using statement (as I did above). This ensures that the IDisposable is properly cleaned up (ie releases File System handles).
I'm trying to serialize an array of objects and a string. This is the serialization code:
FileStream s;
s = new FileStream(savefile.FileName, FileMode.Create, FileAccess.Write);
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(s, ch.chaps);
bf.Serialize(s, txtPassword.Text);
s.Close();
This is the deserialization code:
FileStream s;
s = new FileStream(openfile.FileName, FileMode.Open, FileAccess.Read);
BinaryFormatter bf = new BinaryFormatter();
string password = (string)bf.Deserialize(s);
ch.chaps = (Chapter[])bf.Deserialize(s);
s.Close();
int i;
if (password == txtPassword.Text)
{
for (i = 0; i <= 1000; i++)
{
try
{
combChapSelect.Items.Add(ch.chaps[i].chapName);
}
catch
{
i = 1000;
}
}
}
This is the code and visual studio says there are no errors but the openfiledialog doesn't close when I select a file and nothing happens. Have I done something wrong or is there another way to serialize different object types?
You're doing this backwards. You have to deserialize in the same order that you serialize.
In your serialization, its chaps-then-password. In your deserialization, its password-then-chaps.
I am facing this problem
class person
{
;
}
person p = new person();
XmlSerializer ser = new XmlSerializer(p.GetType());
FileStream fs = File.Open("sam.xml",FileMode.OpenOrCreate, FileAccess.Write);
ser.Serialize(fs,p)
fs.flush();
fs.close();
FileStream stream = FileStream("sam.xml", FileMode.Open);
XmlDictionaryReader xdr = XmlDictionaryReader.CreateTextReader(stream,new XmlDictionaryReaderQuotas());
now my problem is how can i create xdr object without creating xml files.
You can do it with a memory stream like that:
class person
{
;
}
person p = new person();
using (MemoryStream ms = new MemoryStream())
{
XmlSerializer ser = new XmlSerializer(p.GetType());
ser.Serialize(ms,p)
ms.Seek(0, SeekOrigin.Begin);
XmlDictionaryReader xdr = XmlDictionaryReader.CreateTextReader(ms,new XmlDictionaryReaderQuotas());
}
That should work.
Serialize to a memorystream instead of a filestream.
I have a generic class as follows:
class myClass<T>
{
public T[] m_SomeData;
}
I want to implement a generic method to read data from a file and populate the data fields of this class. Something like:
class myClass<T>
{
public T[] m_SomeData;
public void ReadData(string fileName);
}
An implementation of the ReadData methods looks something like this (all error checking removed for brevity):
void ReadData(string fileName)
{
TextReader rdr = new StreamReader(fileName);
string line = rdr.ReadLine();
// Here I need to parse value of type T from the line
// and initialize the m_SomeData array
// How do I do that? I would like to keep it generic if possible
}
Note, I can guarantee the type T is numeric, at least by convention
Update: OP would like human readable output. I would suggest JavaScriptSerializer, then, in:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Web.Extensions.dll
// Serialize:
using (var fs = new FileStream(fileName, FileMode.Create))
using (var writer = new StreamWriter(fs))
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
string s = serializer.Serialize(m_SomeData);
writer.Write(s);
}
// Deserialize:
using (var fs = new FileStream(fileName, FileMode.Open))
using (var reader = new StreamReader(fs))
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
var s = reader.ReadToEnd();
m_SomeData = serializer.Deserialize<T[]>(s);
}
Old Answer:
This is a job for BinaryFormatter:
using (FileStream fs = new FileStream(fileName, FileMode.Open))
{
BinaryFormatter formatter = new BinaryFormatter();
m_SomeData = (T[])formatter.Deserialize(fs);
}
This of course assumes you are also using it to serialize via formatter.Serialize(fs, m_SomeData);.