I have a strange problem in my Windows Phone 7 application. I need to read/write some xml file in my app and I'm using IsolatedStorage to collect data. My app sends/gets data from SkyDrive this is why I use it.
Ok, here is function which generate exception:
private void CreateFileIntoIsolatedStorage(List<Record> list)
{
isf = IsolatedStorageFile.GetUserStoreForApplication();
if(list.Count == 0)
list = new List<Record>() { new Record { Date = DateTime.Today, Value = 0 }};
if (isf.FileExists(fileName))
{
isf.DeleteFile(fileName);
}
XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
xmlWriterSettings.Indent = true;
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream stream = myIsolatedStorage.OpenFile(fileName, FileMode.Create))
{
XmlSerializer serializer = new XmlSerializer(typeof(List<Record>));
using (XmlWriter xmlWriter = XmlWriter.Create(stream, xmlWriterSettings))
{
serializer.Serialize(xmlWriter, list);
}
}
}
}
Problem:
My problem starts when I this function runs for the second time. Then isf.DeleteFile(fileName); throws IsolatedStorageException. And creating stream crashed application.
It's strange cause it happens every time I run it on my device, and rarely when I use the debugger.
So my question is how can I solve it or are there better ways to do this?
Any help would be appreciated.
Possibly it's because at the beginning of your method you have:
isf = IsolatedStorageFile.GetUserStoreForApplication();
And you never dispose of that. Then, later, you get it again in the using. But that one's disposed. And then the next time you call CreateFileIntoIsolatedStorage, you get it again, again without disposing.
Perhaps this is what you want:
using (var isf = IsolatedStorageFile.GetUserStoreForApplication())
{
if(list.Count == 0)
list = new List<Record>() { new Record { Date = DateTime.Today, Value = 0 }};
if (isf.FileExists(fileName))
{
isf.DeleteFile(fileName);
}
}
Although that class-scoped isf variable is troublesome. If you want to keep the store active, then just call it once and leave it open. Otherwise, ditch the class-scoped variable.
Or, it might be due to this, from the documentation for IsolatedStorageFile.DeleteFile?
File deletions are subject to intermittent failures because files can be in use simultaneously by operating system features such as virus scanners and file indexers. This is especially true for recently created files. Macintosh users should be aware of this issue because of its frequent indexing.
For these reasons, it is important to add code to the code block that handles the IsolatedStorageException to retry deleting the file or log a failure.
I would suggest something like:
int retryCount = 0;
while (retryCount < MaxRetryCount && isf.FileExists(fileName))
{
try
{
isf.DeleteFile(fileName);
}
catch (IsolatedStorageException)
{
++retryCount;
// maybe notify user and delay briefly
// or forget about the retry and log an error. Let user try it again.
}
}
Related
I have an xml file which is used by multiple process for reading. Here is the code snippet used for deserializing the xml. I want to make sure the below code does not read lock the file.
public Address TestReadLock(string myXmlFile)
{
using (StreamReader sr = new StreamReader(myXmlFile))
{
XmlReaderSettings xrs = new XmlReaderSettings();
xrs.ValidationType = ValidationType.None;
xrs.XmlResolver = null;
using (XmlReader reader = XmlReader.Create(sr, xrs))
{
return (Address)xmlSerializer.Deserialize(reader);
}
}
}
I tried testing this by creating a dll of above function and loaded the file through powershell and VS in a loop at same time it worked fine.
public void Main()
{
for (int i = 0; i < 1000; i++)
{
Address myaddress = TestReadLock(#C:\MyDetails.xml")
}
}
Based on my understanding the above code should read lock the file nad while testing it is not the case
Is there a possibility like testing I did is wrong or my understanding is not correct?
new StreamReader(string) uses FileAccess.Read and FileShare.Read - it will not prevent other readers. If you want different control: use FileStream directly to control the access / sharing.
I am writing the data and reading it, i am getting the exception as "System.Xml.XmlException: Unexpected XML declaration",i am unable to figure it out whats the issue.
I have also added the exception that its printing.Please help me to solve the issue.
Here my code:
public static void WriteTopicState(Topic topic)
{
try
{
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
{
using (StreamWriter sw = new StreamWriter(store.OpenFile("Stats.xml", FileMode.Append, FileAccess.Write)))
{
XmlSerializer serializer = new XmlSerializer(typeof(Topic));
serializer.Serialize(sw, topic);
serializer = null;
}
}
}
catch (Exception)
{
throw;
}
}
public static Topic ReadMockTestTopicState()
{
Topic topic = null;
try
{
using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())
{
// Read application settings.
if (isoStore.FileExists("Stats.xml"))
{
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
{
using (StreamReader SR = new StreamReader(store.OpenFile("Stats.xml", FileMode.Open, FileAccess.Read)))
{
XmlSerializer serializer = new XmlSerializer(typeof(Topic));
topic = (Topic)serializer.Deserialize(SR);
serializer = null;
}
}
}
else
{
// If setting does not exists return default setting.
topic = new Topic();
}
}
}
catch (Exception)
{
throw;
}
return topic;
}
Exception :
{System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. --->
System.InvalidOperationException: There is an error in XML document (9, 19). --->
System.Xml.XmlException: Unexpected XML declaration. The XML declaration must be the first node in the document, and no white space characters are allowed to appear before it. Line 9, position 19.
EDIT
If there is any other way that i can save the data to a txt file also is fine for me, but only thing is i need to append the data to the existing document and read it get back the data.
Your problem is because you are appending to your Stats.xml document, as a result it will contain multiple root elements once it has been written to more than once.
If you wish to only store the latest stats, you should use FileMode.Create:
using (StreamWriter sw = new StreamWriter(store.OpenFile("Stats.xml", FileMode.Create, FileAccess.Write)))
Valid XmlDocuments can only contain one root element, if you wish to store multiple 'stats' a different strategy is required:
If writes are only creates (eg not updates) write out each topic to a different file and combine them when reading
Create a container element that will store multiple topics and then parse this from disk, add to it, then subsequently overwrite the file on disk (you'll need to be careful with concurrency if you choose this option)
Use a different storage medium than the file system (eg a document database, a SQL database, etc)
Many other options
So I've been working on a simple game and I wanted to implement a highscore system. Once the player loads up the main page for the first time a new text file is created ("hsc.txt") and some fake values are inserted which are later on split up by the program, however, currently my code throws a System.IO.IsolatedStorage.IsolatedStorageException and I can't seem to find the problem. I've looked up the error that I got from the message box which was "- operation not permitted" but all the solutions that were posted don't seem to work. I have tried closing the streams but it doesn't seem to work.
Any advice would be highly appreciated.
private void hasHighscores()
{
String fileName = "hsc.txt";
using (var isoStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!isoStorage.FileExists(fileName))
{
isoStorage.CreateFile(fileName);
using (var isoStream = new IsolatedStorageFileStream(fileName, FileMode.Append, FileAccess.Write, isoStorage))
{
using (var fileStream = new StreamWriter(isoStream))
{
fileStream.WriteLine("n1:666,n2:777,n3:888,h1:666,h2:777,h3:888");
fileStream.Close();
}
isoStream.Close();
}
}
}
}
So far I have: a) changed the FileMode b) changed the FileAccess and a few other "quickfixes" that I don't even remember.
The CreateFile method returns a stream to the created file, and keeps it open. Therefore, when you try to open a stream to that same file in the next line, it throws an exception because the file is already locked.
You can rewrite your code as follows:
private void hasHighscores()
{
String fileName = "hsc.txt";
using (var isoStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!isoStorage.FileExists(fileName))
{
using (var isoStream = isoStorage.CreateFile(fileName))
{
using (var fileStream = new StreamWriter(isoStream))
{
fileStream.WriteLine("n1:666,n2:777,n3:888,h1:666,h2:777,h3:888");
}
}
}
}
}
I've also removed the stream.Close() instructions. The close method is automatically called when you enclose the stream in a using statement.
So I've been working on a simple game and I wanted to implement a highscore system. Once the player loads up the main page for the first time a new text file is created ("hsc.txt") and some fake values are inserted which are later on split up by the program, however, currently my code throws a System.IO.IsolatedStorage.IsolatedStorageException and I can't seem to find the problem. I've looked up the error that I got from the message box which was "- operation not permitted" but all the solutions that were posted don't seem to work. I have tried closing the streams but it doesn't seem to work.
Any advice would be highly appreciated.
private void hasHighscores()
{
String fileName = "hsc.txt";
using (var isoStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!isoStorage.FileExists(fileName))
{
isoStorage.CreateFile(fileName);
using (var isoStream = new IsolatedStorageFileStream(fileName, FileMode.Append, FileAccess.Write, isoStorage))
{
using (var fileStream = new StreamWriter(isoStream))
{
fileStream.WriteLine("n1:666,n2:777,n3:888,h1:666,h2:777,h3:888");
fileStream.Close();
}
isoStream.Close();
}
}
}
}
So far I have: a) changed the FileMode b) changed the FileAccess and a few other "quickfixes" that I don't even remember.
The CreateFile method returns a stream to the created file, and keeps it open. Therefore, when you try to open a stream to that same file in the next line, it throws an exception because the file is already locked.
You can rewrite your code as follows:
private void hasHighscores()
{
String fileName = "hsc.txt";
using (var isoStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!isoStorage.FileExists(fileName))
{
using (var isoStream = isoStorage.CreateFile(fileName))
{
using (var fileStream = new StreamWriter(isoStream))
{
fileStream.WriteLine("n1:666,n2:777,n3:888,h1:666,h2:777,h3:888");
}
}
}
}
}
I've also removed the stream.Close() instructions. The close method is automatically called when you enclose the stream in a using statement.
I've read about a thousand similar posts, and have followed the general advice but am still running into the issue. Here's my scenario:
I'm working on a Windows Phone 8 app that, when the user saves, serializes all of their data into XML then uses CreateFile to store it. The problem that I'm facing is that if a user hits save several times consecutively, IsolatedStorageException:Operation Not Permitted is thrown (I'm guessing that the serialization takes long enough that the file is still being used when I attempt to access it a second time). When save is tapped the second time, is there a way for me to abort the previous action, free up the isolated storage file, and initiate the new save? Or is there a better solution?
Here's the code for my Save method (the exception occurs on the isoStore.CreateFile(filename) line):
using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream stream = isoStore.CreateFile(filename))
{
XmlSerializer xml = new XmlSerializer(GetType());
xml.Serialize(stream, this);
}
}
Any help would be amazing, as I've been stuck here for weeks.
Thanks,
Ben:
You could go with something like this.
private async Task Save(string fileName)
{
Button.IsEnabled = false;
await Task.Run(() =>
{
using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream stream = isoStore.CreateFile(filename))
{
XmlSerializer xml = new XmlSerializer(GetType());
xml.Serialize(stream, this);
}
}
});
Button.IsEnabled = true;
}
Why not disable the 'save' button when clicked then enable it again once the serialization completes?