static filestream for saving Xml file, intermittent WinIOError exceptions..

T

Tim_Mac

hi,
i'm not sure if i have chosen the best approach, but it seemed quite
good to me.
i have a collection class, containing business objects. the collection
class is static and remains in-memory all the time the app is running.
it is persisted to an Xml file when necessary. i keep a static
filestream on the xml file. the advantage of this is that i can lock
the filestream object to prevent concurrent reading/writing.

the code works great, but very occassionally, windows spits out a
WinIOError and the Save() method fails while calling SetLength(0) on
the filestream. the error message is:

"The requested operation cannot be performed on a file with a
user-mapped section open"
System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
+2015079
System.IO.FileStream.SetLengthCore(Int64 value) +112
System.IO.FileStream.SetLength(Int64 value) +151

i thought by using "lock" on the filestream that the file i/o would be
safe. but i must be missing something? i searched around google for a
while but didn't find anything to explain why this is happening.

here is the code. it is very simple, with a private 'pages' variable,
and a corresponding public 'Pages' property, which handles
initialisation for first-time access.

public static class PageManager
{
private static PageCollection pages;
private static FileStream fs = new
FileStream(HttpContext.Current.Server.MapPath("~/App_Data/Pages.xml"),
FileMode.OpenOrCreate, FileAccess.ReadWrite);

public static PageCollection Pages
{
get
{
if (pages == null)
{
lock (fs)
{
// read in all the pages into memory
fs.Seek(0, SeekOrigin.Begin);
XmlSerializer xs = new
XmlSerializer(typeof(PageCollection));
pages = xs.Deserialize(fs) as PageCollection;
}
}
return pages;
}
}

public static void Save()
{
lock (fs)
{
fs.SetLength(0); // wipe the file contents
fs.Seek(0, SeekOrigin.Begin);
XmlSerializer xs = new
XmlSerializer(typeof(PageCollection));
xs.Serialize(fs, pages);
}
}
}

thanks for any tips!
tim
 
S

Scott Allen

I think your code uses lock correctly - but there can be a lot more
interaction between the OS and the file system in-between those locks.
I don't know if a call to Flush() before calling SetLengh will work or
not - you might have to close the file before truncating.
 
Y

Yuan Ren[MSFT]

Hi Tim,

Thanks for your posting!

As Scott's description, the lock syntax is used correctly in your code. As
far as I know, the error message usually indicates the file is used by
other applications or processes. So you need to consider whether there are
others applications use the file when SetLength method executing.

In additional, I suggest you use close or dispose method to release
reference of file stream object. This could prevent the problem occurring
frequently.

I appreciate your understanding and hope the above information helps, if
you have any issues or concerns please let me know. I will be happy to be
of further assistance.

Regards,

Yuan Ren [MSFT]
Microsoft Online Support
 
T

Tim_Mac

hi Yuan,
thanks for your helpful post. it was my impression that if i took out
a static read+write filestream on the file, that other applications
would not be allowed to access it. e.g. indexing service, google
desktop search, etc. i don't want other appliactions to go near the
file if possible. is my understanding correct? or is there an easier
way to wipe a file before writing to it?
thank you
tim
 
Y

Yuan Ren[MSFT]

Hi Tim,

Thanks for your reply!

You are correct! When you create a file stream object instance for file, it
just means there is a variable in memory which has referenced to file but
no opened the file.
So if there are other applications or process using the file, you will get
IO error when handling it.
"is there an easier way to wipe a file before writing to it?"

Based on my experience, catching the current error is a good way. And then,
you could give the client some reminder like "The file can not be updated
now, please try later ..." or something else.

I hope my suggestion is helpful.

Merry Christmas and Happy New Year!

Yuan Ren [MSFT]
Microsoft Online Support
 
T

Tim_Mac

hi Yuan,
thanks for the explanation. what i need to do is make sure no other
processes, .net or indexing service, antivirus etc., are allowed to
prevent me from writing to the file when i need to.
i see there is a FileStream.Lock() method, but because the size of the
file changes regularly, this would need some maintenance to keep the
lock range synchronised with the size of the file. Is there another
way to completely lock out the file from all other processes?
thanks
tim
 
T

Tim_Mac

sorry, i found the answer. use FileShare.Write or whichever option is
best for your situation. this stops all proceses writing to the file.
the docs say all processes including the current one, but my experience
is that the current process can write to the file as long as it is
using the file stream object that declared the FileShare option.

thanks for your help yuan.
tim
 
Y

Yuan Ren[MSFT]

Hi Tim,

You are welcome!

I'm glad to hear your problem has been resolved! If you have any issues in
the future, it's my pleasure to be of assistance.

Regards,

Yuan Ren [MSFT]
Microsoft Online Support
 
T

Tim_Mac

just a correction to my previous post, the meaning of the FileShare.xxx
option is related to how you want the file to be shared. if you
choose FileShare.None it means nobody can share the file (read or
write). FileShare.Read means other processes can read the file but not
write to it, which is the option i found most useful.
 
Y

Yuan Ren[MSFT]

Hi Tim,

Thanks for your sharing knowledge:)

Yuan Ren [MSFT]
Microsoft Online Support
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top