I'm using code bellow to serialize data into myObject
public static void SerializeObject(string filename, MyObject objectToSerialize)
{
Stream stream = File.Open(filename, FileMode.Create);
BinaryFormatter bformatter = new BinaryFormatter();
bformatter.Serialize(stream, objectToSerialize);
stream.Close();
}
This code works fine, but I'm having problem with deleting temporary files (here presented as parameter (filename)).
I'm assuming that problem is in this method code above, so how can I release any resource this code uses so I can delete file.
I did not have any problems deleting the file when I tried your program but I think you should be using the following:
public static void SerializeObject(string filename, MyObject objectToSerialize)
{
var stream = File.Open(filename, FileMode.Create);
BinaryFormatter bformatter = new BinaryFormatter();
bformatter.Serialize(stream, objectToSerialize);
stream.Close();
}
I am not sure that converting to a Stream a FileStream causes any issues, it probably does not anyway.
But this is even probably easier and more fool proof as it ensures that the stream gets closed properly:
public static void SerializeObject(string filename, Object objectToSerialize)
{
using (var stream = File.Open(filename, FileMode.Create))
{
BinaryFormatter bformatter = new BinaryFormatter();
bformatter.Serialize(stream, objectToSerialize);
}
}
If you find a way to reproduce your issue, let me know: as I mentioned, I could delete the file after executing your function and while still running the program, so I cannot reproduce your issue.
Related
I onced managed to create the bin-file in my project. I changed the primary key from int to Guid and moved code from Main to my class Quote. At the moment I can only add new entries in said file. If I remove it a new file(0 bytes) is created and the stream gets ArgumentException when I try to feed the file dummy-data. I am trying to use an if-loop to handle stream.Lenght == 0.
public static List<Quote> readBinaryToList() //Crashes if binfile is 0 bytes long
{
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream(#"C:\Users\xxxxxx\Desktop\quotes.bin", FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read);
if (stream.Length == 0)
{
Quote q = new Quote(Guid.NewGuid(), "Quote dummy", false);
List<Quote> quoteList = new List<Quote>();
quoteList.Add(q);
var bformatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
bformatter.Serialize(stream, quoteList);
bformatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
List<Quote> quoteListTmp = (List<Quote>)bformatter.Deserialize(stream);
return quoteList;
}
else
{
List<Quote> quoteList = (List<Quote>)formatter.Deserialize(stream);
stream.Close();
return quoteList;
}
}
As pointed out in previous answers, you must give your file stream write permissions which can be done in its constructor, then you should also set the position of the stream back to 0, you can achieve this by using the stream's Position property.
You are creating a lot of unnecessary objects that don't actually contribute to purpose of the method I have omitted these below. In doing so, setting the streams Position property to 0 is redundant but I've left it in a comment to show how its done.
Some other things to consider: Declare the file stream inside a using statement so that it is disposed when the method comes to an end this means you can omit the manual close in the else statement. Some of your code can be written more tersely, this is just a personal preference but I think it would be best to inline some of your code to remove as much noise as possible. It is also convention in C# to use PascalCase for Methods.
public static List<Quote> ReadBinaryToList(){
using(Stream stream = new FileStream(#"quotes.bin", FileMode.OpenOrCreate, FileAccess.ReadWrite)) {
IFormatter formatter = new BinaryFormatter();
if (stream.Length == 0) {
List<Quote> quoteList = new List<Quote> {new Quote(Guid.NewGuid(), "Quote dummy", false)};
formatter.Serialize(stream, quoteList);
//stream.Position = 0;
return quoteList;
}
else return (List<Quote>)formatter.Deserialize(stream);
}
}
The file is being opened as readonly, serializing to the file will require write permissions.
Stream stream = new FileStream(#"C:\temp\quotes.bin", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
The stream should also be returned to the beginning before making any attempts to deserialize from it.
stream.Seek(0, SeekOrigin.Begin);
FileStreams have a single "head" where all read and write operations take places. As a new stream is being written, the head is always at the end and any attempt to read from the end will fail. Some streams (e.g. NetworkStream) behave differently and do not allow seeking at all.
Also, the initial position of the FileStream depends on how the file is opened (based on the specified FileMode). The FileMode specified in the question will result in the stream position starting at the beginning of the file, so this is not required in the else block.
And make sure that the Quote class is marked [Serializable]
public void WriteListToFile(Lists lists, string filePath)
{
FileStream outFile;
BinaryFormatter bFormatter = new BinaryFormatter();
// Ppen file for output
outFile = new FileStream(filePath, FileMode.Create, FileAccess.Write);
// Output object to file via serialization
bFormatter.Serialize(outFile, lists);
// Close file
outFile.Close();
}
Whenever I try to output data to a .dat file I get an error saying that the file is already in use. How do I fix this?
EDT: Turns out it wouldn't let me save to an empty file so I create a new void to input data and then it allowed me to save over the file.
The immediate answer is "release the lock that some process has on the file".
Something already has the file open. You need to look at code and other processes that may access that file to find the root cause.
I note that you're not making use of using statements. If an exception were thrown in the block of code you show, outputFile.Close() would never execute, leaving the file open.
Try rewriting your code (and any similar code) like
public void WriteListToFile(Lists lists, string filePath)
{
BinaryFormatter bFormatter = new BinaryFormatter();
// Ppen file for output
using (FileStream outFile = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
// Output object to file via serialization
bFormatter.Serialize(outFile, lists);
// Close file
outFile.Close();
}
}
The using keyword is a syntactic shortcut for
var outFile = new FileStream(filePath, FileMode.Create, FileAccess.Write);
try
{
// Do stuff with outFile
}
finally
{
outFile.Dispose();
}
and ensures that outFile is disposed (which also closes it) whether or not an exception is thrown.
you can try this:
outFile.Dispose();
I need to persist a list of object between application launches per user basis; how can I do it?
The object is simple: 4 strings and one int.
Serialize the object to the users appdata directory or use the IsolatedStorage when you want to persist it and deserialize it when launching.
Easiest way is to just store them as user-scoped application settings
Then you can just access them via static properties
MyApplication.Properties.Settings.Default.StringOne = "herpaderp";
MyApplication.Properties.Settings.Default.Save();
Description
One way is to use BinaryFormatter to save a list of serializable objects to a binary file. You can use the SoapFormatter if you want a readable / editable file.
Sample
Here a class that makes it possible to save a list of serializable objects.
[Serializable]
public class BinareObjectList<T> : List<T>
{
public void LoadFromFile(string fileName)
{
if (!File.Exists(fileName))
throw new FileNotFoundException("File not found", fileName);
this.Clear();
try
{
IFormatter formatter = new BinaryFormatter();
// IFormatter formatter = new SoapFormatter();
Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
List<T> list = (List<T>)formatter.Deserialize(stream);
foreach (T o in list)
this.Add(o);
stream.Close();
}
catch { }
}
public void SaveToFile(string fileName)
{
if (File.Exists(fileName))
File.Delete(fileName);
IFormatter formatter = new BinaryFormatter();
// IFormatter formatter = new SoapFormatter();
Stream stream = new FileStream(fileName, FileMode.CreateNew);
formatter.Serialize(stream, this);
stream.Close();
}
}
More Information:
MSDN: BinaryFormatter Class
MSDN: SoapFormatter Class
Update
You said in a comment that you try to save application settings. Consider using Application Settings.
MSDN: Using Settings in C#
I would vote for Isolated Storage.
I'm using : boito = Serializer.DeSerializeObject("XOPC.xml"); with try catch.
so here is method :
public static ObjectToSerialize DeSerializeObject(string filename)
{
ObjectToSerialize objectToSerialize;
Stream stream = File.Open(filename, FileMode.Open);
BinaryFormatter bFormatter = new BinaryFormatter();
objectToSerialize = (ObjectToSerialize)bFormatter.Deserialize(stream);
stream.Close();
return objectToSerialize;
}
I had changed structure and it's failing to DeSerialize this file but on next step when I'm trying to serialize it again I'm getting error : "This file is using by another process" and I can't access it.
So how to stop using file after error in deserialization ?
You're not closing the stream if an exception is thrown. Use a using statement:
using (Stream stream = File.Open(filename, FileMode.Open))
{
BinaryFormatter bFormatter = new BinaryFormatter();
return (ObjectToSerialize) bFormatter.Deserialize(stream);
}
This is equivalent to disposing of the stream in a finally block.
This isn't just about deserialization - you should (almost1) always use using statements for unmanaged resources. Any explicit call to Close or Dispose (outside a Dispose implementation merely releasing composed resources) is suspicious.
1 Very occasionally you want to leave a resource open on success, but close it if something else fails. This is rare and awkward.
Presently I need to serialize one of my object which contains more my own classes object.
But the problem is I dont want to save it in a file and then retrieve it into memory stream.
Is there any way to directly serialize my object into stream.
I used BinaryFormatter for seializing.
First I used a MemoryStream directly to take serialize output but it is giving error
at time of deserialization. But later when I serialize it with a file then close it and
again reopen it , it works perfectly. But I want to take it direct into stream because
in my program I need to do it frequently to pass it into network client. And using file
repeatedly might slow down my software.
Hope I clear my problem. Any Sugetion ?
If you're trying to deserialize from the same MemoryStream, have you remembered to seek back to the beginning of the stream first?
var foo = "foo";
var formatter = new BinaryFormatter();
using (var stream = new MemoryStream())
{
// Serialize.
formatter.Serialize(stream, foo);
// Deserialize.
stream.Seek(0, SeekOrigin.Begin);
foo = formatter.Deserialize(stream) as string;
}
Here's a quick and dirty sample, of serializing back and forth a string. Is this what your trying to do?
static void Main(string[] args)
{
var str = "Hello World";
var stream = Serialize(str);
stream.Position = 0;
var str2 = DeSerialize(stream);
Console.WriteLine(str2);
Console.ReadLine();
}
public static object DeSerialize(MemoryStream stream)
{
BinaryFormatter formatter = new BinaryFormatter();
return formatter.Deserialize(stream);
}
public static MemoryStream Serialize(object data)
{
MemoryStream streamMemory = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(streamMemory, data);
return streamMemory;
}