(De)Serializing multiple items to file - c#

I want to serialize/deserialize multiple object from/to a file. The syntax should be similar to this:
obj.Append(byteArray);
obj.Append(byteArray);
obj.Append(byteArray);
IEnumerable<byte[]> obj.Extract();
While this is very simple to accomplish (e.g., write a class that uses a filestream and protobuf-net internally), I'm wondering if there is any more elegant way of doing this. Is there any class (from a third party library), that uses a serializer to write to an filestream?
Edit: I need this as a filestream that captures video data that is sent through network. So the filestream must be open for a dedicated amount of time. My previous solution was to save every video frame to a new file, but it's not scalable (especially for hdd, and increasing video partners).

What about:
using(var stream = File.Open(filename, FileMode.Create))
{
var formatter = new BinaryFormatter();
formatter.Serialize(stream, firstObjectToSerialize);
formatter.Serialize(stream, secondObjectToSerialize);
}

Related

Why does my binary file get rewritten each time?

I'm trying to write a binary file with a dictionary of pattern objects. However, the problem I'm facing currently is that my binary file always just has one pattern object only. The previous pattern object gets rewritten by a new one whenever I add it to the dictionary.
I am not able to see how it's doing that as I serialize the entire dictionary after the data stream is created. So it should end up writing all the pattern objects to the binary file.
Here is the code snippet:
Pattern newPatternObject = new Pattern(filename, savedDistanceList, patternTangibleList);
PatternDictionary.Add(filename, newPatternObject);
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream("Pattern.bin", FileMode.Create, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, PatternDictionary);
stream.Close();
Any help will be much appreciated. Thank you.
Change your FileMode.Create to FileMode.Append

Can I send an obj of a class to a file using filestream in C#?

I was wondering if I can send a whole obj which has 4 members:
string name
string lastname
int StudentID
int CitizenID
using the filestream commends to save in a .txt file in binary format?
I know of Serialization, and it sends an obj to a .xml file quite easily, but when I made my program using it and showed it to my teacher, he said he don't want me to use it, said I have to use the base filestream commands like fstream, instream, outstream and ... in C++ , and told me he want a binary format saved .txt file.
Now my question is, can I send a whole obj to a .txt file in C# or do i have to send it like a string, which will be quite a lot of work.
Because I have to turn all members to string then put a indicator or something at end of each so I can read from them later and separate them.
now my question is , can i send a whole obj to a .txt file in C# or do i have to send it like a string ... which will be quite a lot of work ,
Yes, there is a name for this: serialization. Whether you do it manually in your own code, or using one of a range of existing serialization libraries, it is serialization. If your teacher doesn't want you using a serialization library, then you would have to do it in your own code. Which is frankly stupid. I wonder if the teacher wants you to write raw commands to the hard disk as well, to avoid all those silly abstractions like a HAL, OS, or common class libraries...
It may be worth clarifying with your teacher exactly what is, and is not, acceptable. For example, would a binary serializer suffice? I could name several. Would it be OK to use BinaryWriter / BinaryReader? Or is the intent of the exercise to make you think about what you need to do to serialize/deserialize? If the latter: then yes, learn about streams, encodings, and framing protocols (sentinel-values vs length-prefixed data, etc).
I'd use this...
void saveInBinary()
{
IFormatter binaryFormatter = new BinaryFormatter();
Stream binaryStream = new FileStream("File Path Here", FileMode.Create, FileAccess.Write, FileShare.None);
binaryFormatter.Serialize(binaryStream, this);
binaryStream.Close();
}
Stick that in the object's member space, and just call it.
Or, something a bit more useful...
void saveInBinary(object o)
{
IFormatter binaryFormatter = new BinaryFormatter();
Stream binaryStream = new FileStream("File Path Here", FileMode.Create, FileAccess.Write, FileShare.None);
binaryFormatter.Serialize(binaryStream, o);
binaryStream.Close();
}
This will serialize any object passed to it.
Last variation (I promise!) :p
void saveInBinary(object o, string filePath)
{
IFormatter binaryFormatter = new BinaryFormatter();
Stream binaryStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None);
binaryFormatter.Serialize(binaryStream, o);
binaryStream.Close();
}
This one allows you to pass an object and a filepath to the method to serialize the passed object to the passed filepath.
Of course, this will not allow you to read the contents of the .txt file. It'll look like mumbo jumbo. If your intent is to write the data to a human readable file, well, there are tons of examples for that. :p I just provided the serialization stuff because it took me a while to figure it out. ;)
Edit: Shoot. I forgot some code...
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
Code needs those to work (for the IFormatter) Also, for Stream to work, you need to use
using System.IO;
Sorry for forgetting.
Edit 2: Forgot to mention, you'll need to use the [Serializeable] tag on the object(s) you wish to serialize this way. Just put "[Serializeable]" on top of the class you want to serialize.
[Serializeable]
class SerializeableObject
{
string aString;
void aMethod()
{
}
}
Like so.

Deserialize on the fly, or LINQ to XML

Working with C# Visual Studio 2008, MVC1.
I'm creating an xml file by fetching one from a WebService and adding some nodes to it. Now I wanted to deserialize it to a class which is the model used to strongtyped the View.
First of all, I'm facing problems to achieve that without storing the xml in the filesystem cause I don't know how this serialize and deserialize work. I guess there's a way and it's a matter of time.
But, searching for the previous in the web I came accross LINQ to XML and now I doubt whether is better to use it.
The xml would be formed by some clients details, and basically I will use all of them.
Any hint?
Thanks!!
You can save a XElement to and from a MemoryStream (no need to save it to a file stream)
MemoryStream ms = new MemoryStream();
XmlWriter xw = XmlWriter.Create(ms);
document.Save(xw);
xw.Flush();
Then if you reset the position back to 0 you can deserialize it using the DataContractSerializer.
ms.Position = 0;
DataContractSerializer serializer = new DataContractSerializer(typeof(Model));
Model model = (model) serializer.ReadObject(ms);
There are other options for how serialization works, so if this is not what you have, let me know what you are using and I will help.
try this:
XmlSerializer xmls = new XmlSerializer(typeof(XElement));
FileStream FStream;
try
{
FStream = new FileStream(doctorsPath, FileMode.Open);
_Doctors = (XElement)xmls.Deserialize(FStream); FStream.Close();
FStream = new FileStream(patientsPath, FileMode.Open);
_Patients = (XElement)xmls.Deserialize(FStream)
FStream.Close();
FStream = new FileStream(treatmentsPath, FileMode.Open);
_Treatments = (XElement)xmls.Deserialize(FStream);
FStream.Close();
}
catch
{ }
This will load all of the XML files into our XElement variables. The try – catch block is a form of exception handling that ensures that if one of the functions in the try block throws an exception, the program will jump to the catch section where nothing will happen. When working with files, especially reading files, it is a good idea to work with try – catch.
LINQ to XML is an excellent feature. You can always rely on that. You don't need to write or read or data from file. You can specify either string or stream to the XDocument
There are enough ways to load an XML element to the XDocument object. See the appropriate Load functions. Once you load the content, you can easily add/remove the elements and later you can save to disk if you want.

WPF : Can BinaryFormatter serialize FlowDocument instance?

I like to using binaryformatter to serializing flow document. but it makes exception.
[Serializable]
public class BinFlow
{
public FlowDocument my { get; set; }
}
BinFlow myBF = new BinFlow();
myBF.my = myFlowDocument;
FileStream myFile = File.Create(#"d:\test.bin");
BinaryFormatter myBinaryFormat = new BinaryFormatter();
//exception occured here!!
myBinaryFormat.Serialize(myFile, myBF);
Exception message said "FlowDocument does not decared 'Serializable' proeprty".
ps. Of cause, I can use XamlReader and XamlWriter for serializing of FlowDocument. but I think binary can more fast performance for this work.
I am assuming you are asking for your related question -- to shuttle your FlowDocument from one thread to another. I've never had any success using BinaryFormatter. Unless your FlowDocument is very large (say, more than 100 MB), you can easily save it to memory to share between threads as a memory stream like this:
MemoryStream stream = new MemoryStream();
XamlWriter.Save(myFlowDoc, stream);
stream.Position = 0;
You can share MemoryStream between threads, and avoid disk IO. On your other thread, use XamlReader.Load from the MemoryStream.
If you do want to write it to disk in a binary format I'd say get the Xaml, then use the compression libraries to make a ZIP file, as XPS does.

In C#, if 2 processes are reading and writing to the same file, what is the best way to avoid process locking exceptions?

With the following file reading code:
using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.None))
{
using (TextReader tr = new StreamReader(fileStream))
{
string fileContents = tr.ReadToEnd();
}
}
And the following file write code:
using (TextWriter tw = new StreamWriter(fileName))
{
tw.Write(fileContents);
tw.Close();
}
The following exception details are seen:
The process cannot access the file
'c:\temp\myfile.txt' because it is
being used by another process.
What is the best way of avoiding this? Does the reader need to retry upon receipt of the exception or is there some better way?
Note that the reader process is using a FileSystemWatcher to know when the file has changed.
Also note that, in this instance, I'm not looking for alternatives ways of sharing strings between the 2 processes.
You can open a file for writing and only lock write access, thereby allowing others to still read the file.
For example,
using (FileStream stream = new FileStream(#"C:\Myfile.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
{
// Do your writing here.
}
Other file access just opens the file for reading and not writing, and allows readwrite sharing.
using (FileStream stream = new FileStream(#"C:\Myfile.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
// Does reading here.
}
If you want to ensure that readers will always read an up-to-date file, you will either need to use a locking file that indicates someone is writing to the file (though you may get a race condition if not carefully implemented) or make sure you block write-sharing when opening to read and handle the exception so you can try again until you get exclusive access.
If you create a named Mutex you can define the mutex in the writing application, and have the reading application wait until the mutex is released.
So in the notification process that is currently working with the FileSystemWatcher, simply check to see if you need to wait for the mutex, if you do, it will wait, then process.
Here is a VB example of a Mutex like this that I found, it should be easy enough to convert to C#.
Get your process to check the status of the file if it is being written to. You can do this by the presence of a lock file (i.e. the presence of this other file, which can be empty, prevents writing to the main file).
Even this is not failsafe however, as the two processes may create the lock file at the same time - but you can check for this before you commit the write.
If your process encounters a lock file then get it to simply sleep/wait and try again at a predefined interval in the future.
Is there any particular reason for opening the file with FileShare.None? That'll prevent the file from being opened by any other process.
FileShare.Write or FileShare.ReadWrite should allow the other process (subject to permissions) to open and write to the file while you are reading it, however you'll have to watch for the file changing underneath you while you read it - simply buffering the contents upon opening may help here.
All of these answers, however, are equally valid - the best solution depends on exactly what you're trying to do with the file: if it's important to read it while guaranteeing it doesn't change, then lock it and handle the subsequent exception in your writing code; if it's important to read and write to it at the same time, then change the FileShare constant.
You can use a Mutex object for this.
The reader and writer both need retry mechanisms. Also FileShare should be set to FileShare.read for the readers and FileShare.none for the writer. This should ensure that the readers don't read the file while writing is in progress.
The reader (excluding retry) becomes
using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (TextReader tr = new StreamReader(fileStream))
{
string fileContents = tr.ReadToEnd();
}
}
The writer (excluding retry) becomes:
FileStream fileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
using (TextWriter tw = new StreamWriter(fileStream))
{
tw.Write(fileContents);
tw.Close();
}
Write to a temp file, when finished writing rename/move the file to the location and/or name that the reader is looking for.
The best thing to do, is to put an application protocol on top of a file transfer/ownership transfer mechanism. The "lock-file" mechanism is an old UNIX hack that has been around for ages. The best thing to do, is to just "hand" the file over to the reader. There are lots of ways to do this. You can create the file with a random file name, and then "give" that name to the reader. That would allow the writer to asynchronously write another file. Think of how the "web page" works. A web page has a "link" to more information in it, for images, scripts, external content etc. The server hands you that page, because it's a coherent view of the "resource" you want. Your browser then goes and gets the appropriate content, based on what the page description (the HTML file or other returned content), and then transfers what it needs.
This is the most resilient type of "sharing" mechanism to use. Write the file, share the name, move to the next file. The "sharing the name" part, is the atomic hand off that makes sure that both parties (the reader and the writer) agree that the content is "complete."

Categories