I have seen numerous similar questions and I have really tried all the solutions but none seems to work for me.
This is what I have now:
private readonly object _lock = new object();
List<DataModel> dataList = new List<DataModel>();
lock (_lock)
{
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
try
{
using (IsolatedStorageFileStream stream = myIsolatedStorage.OpenFile("Data.xml", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
XmlSerializer serializer = new XmlSerializer(typeof(List<DataModel>));
dataList = (List<DataModel>)serializer.Deserialize(stream);
}
}
catch (IsolatedStorageException e) { e.ToString(); }
}
}
The error occurs on the line using (IsolatedStorageFileStream stream = myIsolatedStorage.OpenFile("Data.xml", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)).
I deduced from the other solutions that I read that this error mainly occurs when I want to write to the file while others are reading it or execute that code block several times concurrently, I end up locking the file."
With the presence of the lock, FileAccess.ReadWrite and FileShare.ReadWrite statements, I'm pretty sure something else is throwing that exception.
My question is what could be throwing the exception (IsolatedStorageException) and how do I take care of it?
There is no InnerException on this one.
Edit: Upon Kookiz suggestion, I'm including this code lines
First, I create my .xml file like this:
public static void createDataXML()
{
List<DataModel> dataList = new List<DataModel>();
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (myIsolatedStorage.FileExists("Data.xml"))
{ return; }
using (IsolatedStorageFileStream stream = myIsolatedStorage.CreateFile("Data.xml"))
{
try
{
XmlSerializer serializer = new XmlSerializer(typeof(List<DataModel>));
serializer.Serialize(stream, dataList);
}
catch
{ }
}
}
}
Later, I populate with this code:
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream stream = myIsolatedStorage.OpenFile("Data.xml", FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
{
XmlSerializer serializer = new XmlSerializer(typeof(List<DataModel>));
using (XmlWriter xmlWriter = XmlWriter.Create(stream, xmlWriterSettings))
{
serializer.Serialize(xmlWriter, dataList);
}
}
}
I know this is a less conventional way of doing this but it IS a way. I was attempting to do something else and this was the result. Just add in the known type you need and this will work
[DataContractAttribute]
[KnownType (typeof(List<String>))]
public class SerializableObject
{
[DataMember]
public List<String> serFile { get; set; }
}
public static Object GetFile(String FileName)
{
try
{
if (!IsolatedStorageFile.GetUserStoreForApplication().FileExists(FileName))
{
throw new System.ArgumentException("File Doesn't Exist In Isoloated Storage");
}
}
catch { return null; }
Object ret = new Object();
try
{
IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();
IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile(#"\" + FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
SerializableObject serList = new SerializableObject();
DataContractSerializer dsc = new DataContractSerializer(serList.GetType());
ret = ((SerializableObject)dsc.ReadObject(fileStream)).serFile;
}
catch (Exception error) { throw new System.ArgumentException(error.Message); }
return ret;
}
The implied task here is that you need to serialize it within a SerializableObject instance. Let me know if you need that code also
Edit
As promised, the savefile function
public static void SaveFile(String FileName, List<String> File)
{
try
{
if (FileName.Length < 1)
{
throw new System.ArgumentException("File Name Must Not Be Empty");
}
if (IsolatedStorageFile.GetUserStoreForApplication().AvailableFreeSpace <= 0)
{
throw new System.ArgumentException("Isolated Storage Out of Memory - Please free up space.");
}
if (IsolatedStorageFile.GetUserStoreForApplication().FileExists(FileName))
{
throw new System.ArgumentException("File Already Exists - Please choose a unique name.");
}
if (File == null)
{
throw new System.ArgumentException("Cannot Save Null Files");
}
}
catch (Exception e)
{
return;
}
try
{
SerializableObject so = new SerializableObject() { serFile = File };
DataContractSerializer dsc = new DataContractSerializer(so.GetType());
IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();
StreamWriter writer;
writer = new StreamWriter(new IsolatedStorageFileStream(FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, file));
dsc.WriteObject(writer.BaseStream, so);
}
catch (Exception error) { throw new System.ArgumentException(error.Message); }
}
Enjoy serializing!
My dear, though this exception of Operation Not Permitted On IsolatedStorage is mainly due to ReadWrite by another thread, in your case it is because of ONE SIMPLE REASON
FileMode.Open throws exception when the filename DOES NOT EXIST
Try with FileMode.OpenOrCreate and it will work like a charm
List<DataModel> dataList = new List<DataModel>();
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream stream = myIsolatedStorage.OpenFile("Data.xml", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
{
XmlSerializer serializer = new XmlSerializer(typeof(List<DataModel>));
dataList = (List<DataModel>)serializer.Deserialize(stream);
}
}
Related
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 want to be able to save images in IsolatedStorage, and later get it.
for this purpose I wrote a helper which I want to access it from everywhere in my app:
for creating an image:
public static void SaveImage(Stream image, string name)
{
try
{
IsolatedStorageFile isolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
if (!isolatedStorage.DirectoryExists("MyImages"))
{
isolatedStorage.CreateDirectory("MyImages");
}
var filePath = Path.Combine("MyImages", name + ".jpg");
using (IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream(filePath, FileMode.Create, isolatedStorage))
{
StreamWriter sw = new StreamWriter(fileStream);
sw.Write(image);
sw.Close();
}
}
catch (Exception ex)
{
throw new Exception("failed");
}
}
and for getting that image again:
public static BitmapImage Get(string name)
{
try
{
IsolatedStorageFile isolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
var filePath = Path.Combine("MyImages", name + ".jpg");
using (IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream(filePath, FileMode.Open, isolatedStorage))
{
BitmapImage image = new BitmapImage();
image.SetSource(fileStream);
return image;
}
}
catch (Exception ex)
{
throw new Exception("failed");
}
}
The problem appears when I try to set source of image I get this error message:
The component cannot be found. (Exception from HRESULT: 0x88982F50)
Assuming you have the right Capabilities under your WMAppManifest.xml what you need is:
public static void SaveImage(Stream image, string name)
{
var bitmap = new BitmapImage();
bitmap.SetSource(attachmentStream);
var wb = new WriteableBitmap(bitmap);
var temp = new MemoryStream();
wb.SaveJpeg(temp, wb.PixelWidth, wb.PixelHeight, 0, 50);
using (var myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!myIsolatedStorage.DirectoryExists("MyImages"))
{
myIsolatedStorage.CreateDirectory("MyImages");
}
var filePath = Path.Combine("MyImages", name + ".jpg");
using (IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream(filePath, FileMode.Create, myIsolatedStorage))
{
fileStream.Write(((MemoryStream)temp).ToArray(), 0, ((MemoryStream)temp).ToArray().Length);
fileStream.Close();
}
}
}
That should work and store your image as a jpeg into your desired directory. if it doesn't, make sure that the create directory and Path.Combine() methods are being used correctly.
I had asked a question here: The process cannot access the file because it is being used by another process: Correct way to read\write to a file: heavily used application-Part II.
We have a heavily used .Net 3.5 application that reads "expensive to create" data and caches it. However we are getting a lot of errors around both reading the cache file and writing to the cache file. I have a single process, multiple threads and I want the application to synchronize access to a resource. I was advised to use a simple locking mechanism like lock or ReaderWriterLockSlim (see: http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx). This however seems to have made the problem much much worse in production.
EDIT
After the change was implemented, a lot of the cache files have a ">" tag in the end. Due to this the files are no longer xml files.
Can someone look at the code and advise what could I be doing wrong?
Code before change:
private XmlDocument ReadFromFile()
{
XmlDocument result=null;
string fileSystemPath=FileSystemPath();
try
{
result=new XmlDocument();
using (StreamReader streamReader = new StreamReader(fileSystemPath))
{
result.Load(streamReader);
}
}
catch (FileNotFoundException)
{
result=null;
}
return result;
}
private object thisObject= new object();
private void WriteToFile(string siteID, XmlDocument stuff)
{
string fileSystemPath=FileSystemPath();
lock(thisObject)
{
using (StreamWriter streamWriter = new StreamWriter(fileSystemPath))
{
stuff.Save(streamWriter);
}
}
}
Code after change:
private readonly ReaderWriterLockSlim readerWriterLockSlim = new ReaderWriterLockSlim();
private XmlDocument ReadFromFile()
{
XmlDocument result = null;
var fileSystemPath = FileSystemPath();
readerWriterLockSlim.EnterReadLock();
try
{
result = new XmlDocument();
using (var fileStream = new FileStream(fileSystemPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var streamReader = new StreamReader(fileStream))
{
result.Load(streamReader);
}
}
catch (FileNotFoundException)
{
result = null;
}
finally
{
readerWriterLockSlim.ExitReadLock();
}
return result;
}
private void WriteToFile()
{
var fileSystemPath = FileSystemPath();
readerWriterLockSlim.EnterWriteLock();
try
{
using (var fileStream = new FileStream(fileSystemPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite))
using (var streamWriter = new StreamWriter(fileStream))
{
stuff.Save(streamWriter);
}
}
finally
{
readerWriterLockSlim.ExitWriteLock();
}
}
This code with some little changes should work
private readonly ReaderWriterLockSlim readerWriterLockSlim = new ReaderWriterLockSlim();
private XmlDocument ReadFromFile()
{
XmlDocument result = null;
var fileSystemPath = FileSystemPath();
readerWriterLockSlim.EnterReadLock();
try
{
result = new XmlDocument();
using (var streamReader = new StreamReader(fileStream))
{
result.Load(streamReader);
}
}
catch (FileNotFoundException)
{
result = null;
}
finally
{
readerWriterLockSlim.ExitReadLock();
}
return result;
}
private void WriteToFile(XmlDocument stuff)
{
var fileSystemPath = FileSystemPath();
readerWriterLockSlim.EnterWriteLock();
try
{
using (var streamWriter = new StreamWriter(fileSystemPath))
{
stuff.Save(streamWriter);
}
}
finally
{
readerWriterLockSlim.ExitWriteLock();
}
}
I am using this code to read values from an isolated storage
IsolatedStorageFile isoStore = null;
StreamReader reader = null;
IsolatedStorageFileStream isolatedStorageFileStream = null;
String strIsolatedStorageValue = string.Empty;
isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Assembly, null, null);
try
{
isolatedStorageFileStream = new IsolatedStorageFileStream(strKey + ".txt", FileMode.OpenOrCreate, isoStore);
// This code opens the store and reads the string.
reader = new StreamReader(isolatedStorageFileStream);
// Read a line from the file and add it to sb.
strIsolatedStorageValue = reader.ReadLine();
}
catch (Exception)
{
}
finally
{
if (isolatedStorageFileStream != null)
{
isolatedStorageFileStream.Dispose();
}
if (reader != null)
{
reader.Dispose();
}
}
// Return the string.
return strIsolatedStorageValue;
The problem is that when I am disposing isolatedStorageFileStream and then disposing the reader, visual studio tells me that isolatedStorageFileStream could be disposed more than once! and when not disposing it I am getting the warning that isolatedStorageFileStream should be disposed first.
What to do in such a case, that is disposing an object used in the constructor of another disposable object
Thanks
You should dispose the reader before the filestream.
To simplify your code, you should make use of using blocks. They do the try/finally/dispose pattern automagically for you:
using (isolatedStorageFileStream = new IsolatedStorageFileStream(
strKey + ".txt", FileMode.OpenOrCreate, isoStore)) {
// This code opens the store and reads the string.
using (reader = new StreamReader(isolatedStorageFileStream)) {
strIsolatedStorageValue = reader.ReadLine();
}
}
Use the using keyword:
using (IsolatedStorageFileStream isolatedStorageFileStream =
new IsolatedStorageFileStream(
strKey + ".txt", FileMode.OpenOrCreate, isoStore))
using (StreamReader reader = new StreamReader(isolatedStorageFileStream))
{
// Read a line from the file and add it to sb.
strIsolatedStorageValue = reader.ReadLine();
}
return strIsolatedStorageValue;
using safely calls Dispose for you and you don't have to call it manually.
The using statement automatically does try-finally for IDisposable (dispose if not null) for you.
using (IsolatedStorageFileStream isolatedStorageFileStream = new IsolatedStorageFileStream(strKey + ".txt", FileMode.OpenOrCreate, isoStore))
{
using (StreamReader reader = new StreamReader(isolatedStorageFileStream))
{
string strIsolatedStorageValue = reader.ReadLine();
return strIsolatedStorageValue;
}
}
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();
}
}