Opening a file with multiple objects - c#

I'm trying to open and display a file that has multiple objects in it (array). I am able to open a file and display only the first object inside the file, but I want to be able to open and display all the object inside the file.
Here is how I tried it:
public T BinaryFileDeSerialize<T>(string filePath)
{
FileStream fileStream = null;
Object obj;
try
{
if (!File.Exists(filePath))
throw new FileNotFoundException("The file" + " was not found. ", filePath);
fileStream = new FileStream(filePath, FileMode.Open);
BinaryFormatter b = new BinaryFormatter(); obj = b.Deserialize(fileStream);
}
catch
{
throw;
}
finally
{
if (fileStream != null)
fileStream.Close();
}
return (T)obj;
}
MainForm:
private Animal ReadFile(string filename)
{
BinSerializerUtility BinSerial = new BinSerializerUtility();
Animal str = BinSerial.BinaryFileDeSerialize<Animal>(filename);
return str;
}
private void mnuFileOpen_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
string thefilename = openFileDialog1.FileName;
Animal msg = ReadFile(thefilename);
if (msg != null)
{
Resultlst.Items.Add(msg);
}
else
UpdateResults();
}
}
I'm not getting any error. The problem is that it opens and display only the first object in the file. I want it to open and display all the objects in that file.
UPDATE:
This is how I Serialized it:
public void BinaryFileSerialize(object[] objs, string filePath)
{
FileStream fileStream = null;
try
{
fileStream = new FileStream(filePath, FileMode.Create);
BinaryFormatter b = new BinaryFormatter();
foreach (var obj in objs)
{
b.Serialize(fileStream, obj);
}
}
catch
{
throw;
}
finally
{
if (fileStream != null)
fileStream.Close();
}
}
UPDATE 2:
public T BinaryFileDeSerialize<T>(string filePath)
{
FileStream fileStream = null;
Object obj;
if (!File.Exists(filePath))
throw new FileNotFoundException("The file" + " was not found. ", filePath);
using (var thefileStream = new FileStream(filePath, FileMode.Open))
{
BinaryFormatter b = new BinaryFormatter();
obj = b.Deserialize(thefileStream);
}
return (T)obj;
}
private Animal[] ReadFile(string filename)
{
BinSerializerUtility BinSerial = new BinSerializerUtility();
var animals = BinSerial.BinaryFileDeSerialize<Animal[]>(filename);
return animals;
}
private void mnuFileOpen_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
string thefilename = openFileDialog1.FileName;
Animal []msg = ReadFile(thefilename);
if (msg != null)
{
Resultlst.Items.Add(msg);
}
else
UpdateResults();
}
I'm getting error:
Failed to convert an object of type Namespace.Animal to type
System.Collections.Generic.List`1 [Namespace.Animal].
The error comes from this return (T)obj;

If you want to use the current serializer you should change deserialize methos as follow:
public IList<T> BinaryFileDeSerialize<T>(string filePath) where T: class
{
var list = new List<T>();
if (!File.Exists(filePath))
throw new FileNotFoundException("The file" + " was not found. ", filePath);
using(var fileStream = new FileStream(filePath, FileMode.Open))
{
BinaryFormatter b = new BinaryFormatter();
while(fileStream.Position < fileStream.Length)
list.Add((T)b.Deserialize(fileStream));
}
return list;
}
And ReadFile should be like this:
private Animal[] ReadFile(string filename)
{
BinSerializerUtility BinSerial = new BinSerializerUtility();
var animals = BinSerial.BinaryFileDeSerialize<Animal>(filename);
return animals.ToArray();
}
private void mnuFileOpen_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
string thefilename = openFileDialog1.FileName;
var messages = ReadFile(thefilename);
if (messages != null)
{
messages.ToList().ForEach(msg =>
Resultlst.Items.Add(msg));
}
else
{
UpdateResults();
}
}
}

Silly question, but what happens if you serialize as List<Animal> then try to call BinaryFileDeSerialize<List<Animal>>()?
Also, you can simplify your method thusly with a using statement.
public T BinaryFileDeSerialize<T>(string filePath)
{
FileStream fileStream = null;
Object obj;
if (!File.Exists(filePath))
throw new FileNotFoundException("The file" + " was not found. ", filePath);
using(var fileStream = new FileStream(filePath, FileMode.Open))
{
BinaryFormatter b = new BinaryFormatter();
obj = b.Deserialize(fileStream);
}
return (T)obj;
}
EDIT:
Try these tweaks to your code...
//call via BinaryFileSerialize<Animal>(..., ...);
public void BinaryFileSerialize<T>(T[] objs, string filePath)
{
using(var fileStream = new FileStream(filePath, FileMode.Create))
{
BinaryFormatter b = new BinaryFormatter();
b.Serialize(fileStream, objs);
}
}
private Animal[] ReadFile(string filename)
{
BinSerializerUtility BinSerial = new BinSerializerUtility();
var animals = BinSerial.BinaryFileDeSerialize<Animal[]>(filename);
return animals;
}

Related

Using FileStream to write to a file first time after the file is created gives an exception

I am trying to write some json text. But I get an Exception like
The process cannot access the file C:\blah blah\SystemInActivity.json because it is being used by an other process. But then second time when I run the app after json file is created and then when I write I dont get an exception. Please help.
class ApplicationSettingsViewModel
{
ApplicationSettingsModel model;
MemoryMappedFile mmf = null;
public string FullPath = string.Empty;
//This is not a singleton class but I guess it has to be one but its ok for demonstration.
public ApplicationSettingsViewModel()
{
model = new ApplicationSettingsModel();
CreateFileWithoutMemoryMap();
//MemoryMapped();
}
public string GetDriectory()
{
return Path.GetDirectoryName(FullPath);
}
private void CreateFileWithoutMemoryMap()
{
var info = Directory.CreateDirectory(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "/" + model.Data.Settings.OrcaUISpecificSettings.TimeOutFolder);
string path = Path.Combine(info.FullName + #"\" + model.Data.Settings.OrcaUISpecificSettings.File);
//mmf = MemoryMappedFile.CreateFromFile(path, FileMode.CreateNew, "MyMemoryFile", 1024 * 1024, MemoryMappedFileAccess.ReadWrite);
FullPath = path;
if (!File.Exists(path))
{
File.Create(path);
}
}
public void WriteToFile(string json)
{
try
{
FileStream fileStream = File.Open(FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); //This line giving Exception
fileStream.SetLength(0);
fileStream.Close(); // This flushes the content, too.
using (StreamWriter sw = new StreamWriter(FullPath))
{
sw.Write(json);
}
}
catch (Exception ex)
{
}
}
In the constructor of the MainWindow I am calling the write method
private ApplicationSettingsViewModel AppViewModel;
public MainWindow()
{
InitializeComponent();
//MessageBox.Show("App Started");
AppViewModel = new ApplicationSettingsViewModel();
WriteToFile("Active");
}
public void WriteToFile(string status)
{
var root = new Root();
string jsonString = string.Empty;
root.AllApplications.Add(new DataToWrite() { AppName = "DevOrca", Status = status });
try
{
jsonString = JsonConvert.SerializeObject(root, Formatting.Indented);
}
catch (Exception ex)
{
MessageBox.Show(jsonString);
MessageBox.Show("Exception");
}
mutex.WaitOne();
//Serialize Contents and write
AppViewModel.WriteToFile(jsonString);
//var access = AppViewModel.GetAccessor();
//byte[] bytes = Encoding.ASCII.GetBytes(jsonString);
//access.Write(bytes, 0, bytes.Length);
mutex.ReleaseMutex();
}
File.Create() method opens FileStream to create a file and you need to close it, something like this:
File.Create(path).Close();

How to read excel file data using memory stream?

I want to read Excel file from JSON data which I am sending from ARC, Can anyone help me to sorted out?
public bool ControlAttachment(AttachmentFile file)
{
try
{
if (file != null && file.File != null)
{
string xlsfile = file.File;
string [] xls = {"application/excel","application/vnd.msexcel","xls","xlsx","application/vnd.ms-excel",};
if (xls.ToList().Contains(file.FileType.Trim()))
{
file.FileType = ".xls";
byte[] contents = Convert.FromBase64String(xlsfile);
string LogFilePaths = ConfigurationManager.AppSettings["ExcelMapperPath"];
string fileName = file.FileName.Split('.')[0] + file.FileType;
string LogFile = HttpContext.Current.Server.MapPath(LogFilePaths + file.FileName.Split('.')[0] + file.FileType);
System.IO.File.WriteAllBytes(LogFile, contents);
if (!File.Exists(LogFile))
{
File.Create(LogFile).Dispose();
}
MemoryStream ms = new MemoryStream();
using (var fs = new FileStream(LogFile, FileMode.Open, FileAccess.Write))
{
ms.CopyTo(fs);
ms.Dispose();
}
}
}
return true;
}
catch
{
return false;
}
}

Saving multiple objects to binary file

I'm trying to save multiple object that the user create to a binary file. So far I am able to create a binary file of one object.
public class BinSerializerUtility
{
public void BinaryFileSerialize(object obj, string filePath)
{
FileStream fileStream = null;
try
{
fileStream = new FileStream(filePath, FileMode.Create);
BinaryFormatter b = new BinaryFormatter();
b.Serialize(fileStream, obj);
}
catch
{
throw;
}
finally
{
if (fileStream != null)
fileStream.Close();
}
}
MainForm:
private void SaveToFile(string filename)
{
for (int index = 0; index < animalmgr.Count; index++)
{
Animal animal = animalmgr.GetAt(index);
BinSerializerUtility BinSerial = new BinSerializerUtility();
BinSerial.BinaryFileSerialize(animal, filename);
}
}
private void mnuFileSaveAs_Click(object sender, EventArgs e)
{
//Show save-dialogbox
if(saveFileDialog1.ShowDialog() == DialogResult.OK)
{
string thefilename = saveFileDialog1.FileName;
SaveToFile(thefilename);
}
}
I'm not really sure how to make it so it can save multiple objects to binary file. Do you have any tips?
I did try the following:
public byte[] SerializeArray(object obj)
{
byte[] serializedObject = null;
MemoryStream memStream = null;
try
{
memStream = new MemoryStream();
BinaryFormatter binFormatter = new BinaryFormatter();
binFormatter.Serialize(memStream, obj);
memStream.Seek(0, 0); //set position at 0,0
serializedObject = memStream.ToArray();
}
finally
{
if (memStream != null)
memStream.Close();
}
return serializedObject; // return the array.
}
But the problem with it is that I don't know where to insert the fileName (The path)
You can modify BinaryFileSerialize to accept an array:
public void BinaryFileSerialize(object [] objs, string filePath). Then you can loop over that array to insert each item in the array:
FileStream fileStream = new FileStream(filePath, FileMode.Create);
BinaryFormatter b = new BinaryFormatter();
foreach(var obj in objs) {
b.Serialize(fileStream, obj);
}
SaveToFile function:
private void SaveToFile(string filename)
{
//Animal array
Animal [] animals = new Animal[animalmgr.Count];
for (int index = 0; index < animalmgr.Count; index++)
{
animals[index] = animalmgr.GetAt(index);
}
BinSerializerUtility BinSerial = new BinSerializerUtility();
BinSerial.BinaryFileSerialize(animals, filename);
}

ArgumentNullException when deserializing my object

I can serialize my object in soap formatting, I wrote the directory in the string variable fullPath but when I try to deserialize it, it shows me ArgumentNullException, why?
//The code in form1.
Train tr = new Train();
fullPath = "D:\\file.xml";
tr.WriteToFile(fullPath);
//WriteToFile() method in Train class.
public void WriteToFile(string path)
{
using (FileStream stream = new FileStream(path, FileMode.Create))
{
SoapFormatter formatter = new SoapFormatter();
formatter.Serialize(stream, this);
}
}
//The code in Form2
Form1 f = new Form1();
string fullPath = f.fullPath;
try
{
using (Stream stream = File.OpenRead(f.fullPath))
{
SoapFormatter formatter = new SoapFormatter();
tr = formatter.Deserialize(stream) as Train;
}
}
catch (ArgumentNullException ex)
{
MessageBox.Show("ArgumentNullException: " + ex.Message);
}

How to keep XmlSerializer from killing NewLines in Strings?

Suppose I have a simple Class with just one Member a String.
public class Abc
{
private String text;
public String Text
{
get { return this.text; }
set { this.text = value; }
}
}
Now when I serialize and then deserialize it with the questionable XmlSerializer any text containing newlines ('\r\n' or Environment.NewLine) are transformed to '\n'.
How do I keep the newlines?
It is not the XmlSerializer but the XmlWriter which is removing your CR. To retain it we must have the writer convert CR to its character entity 
.
XmlWriterSettings ws = new XmlWriterSettings();
ws.NewLineHandling = NewLineHandling.Entitize;
XmlSerializer ser = new XmlSerializer( typeof( Abc ) );
using (XmlWriter wr = XmlWriter.Create( "abc.xml", ws )) {
ser.Serialize( wr, s );
}
This is exactly the same with DataContractSerializer:
var ser = new DataContractSerializer( typeof( Abc ) );
using (XmlWriter wr = XmlWriter.Create( "abc.xml", ws )) {
ser.Serialize( wr, s );
}
Why do we need to do this?
This is because compliant XML parsers must, before parsing, translate CRLF and any CR not followed by a LF to a single LF. This behavior is defined in the End-of-Line handling section of the XML 1.0 specification.
As this happens before parsing, you need to encode CR as its character entity if you want the CR to exist in the document.
public class SerializeAny<TF> where TF : new()
{
public static TF Deserialize(string serializedData)
{
try
{
var xmlSerializer = new XmlSerializer(typeof(TF));
TF collection;
using (var xmlReader = new XmlTextReader(serializedData, XmlNodeType.Document, null))
{
collection = (TF)xmlSerializer.Deserialize(xmlReader);
}
return collection;
}
catch (Exception)
{
}
return new TF();
}
public static TF DeserializeZip(string path)
{
try
{
var bytes = File.ReadAllBytes(path);
string serializedData = Unzip(bytes);
TF collection = Deserialize(serializedData);
return collection;
}
catch (Exception)
{
}
return new TF();
}
public static string Serialize(TF options)
{
var xml = "";
try
{
var xmlSerializer = new XmlSerializer(typeof(TF));
using (var stringWriter = new StringWriter())
{
xmlSerializer.Serialize(stringWriter, options);
xml = stringWriter.ToString();
}
}
catch (Exception ex)
{
return ex.Message;
}
return xml;
}
public static string SerializeZip(TF options, string path)
{
var xml = "";
try
{
xml = Serialize(options);
var zip = Zip(xml);
File.WriteAllBytes(path, zip);
}
catch (Exception ex)
{
return ex.Message;
}
return xml;
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
internal static String SerializeObject<T>(T obj, Encoding enc)
{
using (var ms = new MemoryStream())
{
var xmlWriterSettings = new System.Xml.XmlWriterSettings()
{
// If set to true XmlWriter would close MemoryStream automatically and using would then do double dispose
// Code analysis does not understand that. That's why there is a suppress message.
CloseOutput = false,
Encoding = enc,
OmitXmlDeclaration = false,
Indent = true
};
using (var xw = XmlWriter.Create(ms, xmlWriterSettings))
{
var s = new XmlSerializer(typeof(T));
s.Serialize(xw, obj);
}
return enc.GetString(ms.ToArray());
}
}
private static void CopyTo(Stream src, Stream dest)
{
byte[] bytes = new byte[4096];
int cnt;
while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0)
{
dest.Write(bytes, 0, cnt);
}
}
private static byte[] Zip(string str)
{
var bytes = Encoding.UTF8.GetBytes(str);
using (var msi = new MemoryStream(bytes))
using (var mso = new MemoryStream())
{
using (var gs = new GZipStream(mso, CompressionMode.Compress))
{
//msi.CopyTo(gs);
CopyTo(msi, gs);
}
return mso.ToArray();
}
}
private static string Unzip(byte[] bytes)
{
using (var msi = new MemoryStream(bytes))
using (var mso = new MemoryStream())
{
using (var gs = new GZipStream(msi, CompressionMode.Decompress))
{
CopyTo(gs, mso);
}
return Encoding.UTF8.GetString(mso.ToArray());
}
}
}
public class BinarySerialize<T> where T : new()
{
public static string Serialize(T options, string path)
{
var xml = "";
try
{
File.Delete(path);
}
catch (Exception)
{
}
try
{
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
{
var bf = new BinaryFormatter();
bf.Serialize(fs, options);
}
}
catch (Exception ex)
{
return ex.Message;
}
return xml;
}
public static T Deserialize(string path)
{
T filteroptions;
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var bf = new BinaryFormatter();
filteroptions = (T)bf.Deserialize(fs);
}
return filteroptions;
}
}
Use this code:
public static FilterOptions Deserialize(string serializedData)
{
try
{
var xmlSerializer = new XmlSerializer(typeof(FilterOptions));
var xmlReader = new XmlTextReader(serializedData,XmlNodeType.Document,null);
var collection = (FilterOptions)xmlSerializer.Deserialize(xmlReader);
return collection;
}
catch (Exception)
{
}
return new FilterOptions();
}
Nice solution, Lachlan Roche!
The function below (in VB.NET) uses a StringWriter to return a String, rather than writing the result to a file using an XmlWriter.
''' <summary>
''' Exports the object data to an XML formatted string.
''' Maintains CR characters after deserialization.
''' The object must be serializable to work.
''' </summary>
Public Function ExportObjectXml(ByVal obj As Object) As String
If obj Is Nothing Then
Return String.Empty
End If
Dim serializer As New XmlSerializer(obj.GetType)
Dim settings As New XmlWriterSettings With {.NewLineHandling = NewLineHandling.Entitize}
Using output As New StringWriter
Using writer As XmlWriter = XmlWriter.Create(output, settings)
serializer.Serialize(writer, obj)
Return output.ToString
End Using
End Using
End Function

Categories

Resources