problem while writing data into xml, when event occured - c#

I'm trying to write a little software for logging data, if any type of file created in directory A.
I use FileSystemWatcher class to get information about file creation in folder A. There are many subfolder in folder A. And many users can create file in this directory in one time.
I use XML data to save log data.
XmlTextReader reader = new XmlTextReader(FILE_NAME);
XmlDocument doc = new XmlDocument();
doc.Load(reader);
reader.Close();
XmlNode currNode;
XmlDocumentFragment docFrag = doc.CreateDocumentFragment();
docFrag.InnerXml = "<item>" +
"<path>" + fileName + "</path>" +
"<created>0</created>" +
"<date>" + DateTime.ParseExact(DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss"), "dd.MM.yyyy HH:mm:ss", System.Globalization.CultureInfo.CurrentCulture, System.Globalization.DateTimeStyles.None).ToString() + "</date>" +
"</item>";
// insert the availability node into the document
currNode = doc.DocumentElement;
currNode.InsertAfter(docFrag, currNode.LastChild);
//save the output to a file
doc.Save(FILE_NAME);
But sometimes while occurs watcher.Created += new FileSystemEventHandler(OnChanged);, data about file creation is not inserted to XML file.
So, is it possible if file opened for data writing, and it's locked for new dataWrite file document not saved? and how to fix this.

You are in front of a beauty computer problem, please read a bit about the Dining Philosophers problem in http://en.wikipedia.org/wiki/Dining_philosophers_problem .
You can "lock" a file just setting its attribute to ReadOnly
I mean, when you are going to write, you check if "ReadOnly" is set. In that case
System.IO.File.SetAttributes("pathtofile\filename.ext", FileAttributes.ReadOnly);
After writing, please remove the attribute.
A more complex solution could be the use of semaphores, thus controlling yourself the files that are being accessed. You can find a hint here in StackOverflow:
Problem with using Semaphore to protect queue
Also, you can use this link as a hint to really lock files:
How to lock file
Hope that helps,

Seems that sometimes you open file several times and between this operations file is in different states, so when you write it you just overwrite some data written before. I propose you to collect changes in Queue and write them to the file sequentially.

If you need to log data very often, you should either write to database instead of writing to a file or use buffering.

Related

How do I create an already populated text file?

I want to create a text file with the extension .jrq and populate it with two lines. However I want this to happen "all at once" instead of creating the text file and then adding the two lines. Basically I need to create an already populated text file.
Here is my current code:
FileStream fileStream = new FileStream(folder + filename + ".jrq", FileMode.Create);
StreamWriter streamWriter = new StreamWriter(fileStream);
streamWriter.WriteLine("Line1");
streamWriter.WriteLine("Line2");
streamWriter.Flush();
streamWriter.Close();
The reason I need the file creation and the file appending to happen together is because I have a windows service that scans the folder that this text file will be created in and that service triggers a job the second it sees a .jrq file (and does logic based on what's written in the file). It notices the .jrq file before I've written anything in it and throws an error.
I think you are better off using a small trick. As adv12 pointed out writing all at once with one single method does not guarantee the implementation is atomic. if I were you I would create a temporary file:
FileStream fileStream = new FileStream(folder + filename + ".tmp",
FileMode.Create);
StreamWriter streamWriter = new StreamWriter(fileStream);
streamWriter.WriteLine("Line1");
streamWriter.WriteLine("Line2");
streamWriter.Flush();
streamWriter.Close();
and then rename it using File.Move:
System.IO.File.Move(folder + filename + ".tmp",folder + filename + ".jrq");
So the job will start when the file jrq is full of data. it's not a super elegant solution but it would work.
Hope it helps.
You could write the file with a different filename, then move it once you've populated it. According to this question, file moves are atomic within NTFS, so your service would never see a half-written file.
File.WriteAllText is what you're looking for. If the file does not exist, it will create it with the text in it on creation.

Parsing XML file using XMLDocument and moving causes exception

I am trying to read an XML file and export the data to DB. I use XMLDocument to read the contents. After exporting the content i am moving the file to a archive location. To avoid name conflicts before moving i am appending the filename with timestamp. The problem is when i repeatedly export the same xml file at one point in time i am getting an exception "The process cannot access the file because it is being used by another program".
My guess is the xml document loaded in memory is not freed yet. Is there any way to avoid this issue?
UPDATE
I tried all the code related to reading and exporting the xml file. My code now has only these lines
fName = DateTime.Now.ToString("yyyyMMddhhmmss") + fileName;
fName = destinationPath + "\\" + fName;
File.Move(sourcePath, fName);
now when i run it first time it works fine. Then i wait for 2 seconds and then try to export it again now it is throwing me an exception
same xml in one point of time cannot be - at least milliseconds must be different. but i think you will get a lot of files. may be you need change the way

How to modify by loading and saving the same xml file

I have a problem with modifying xml file when i first load and then save it with same file path and name. Below is my code. The error is "Access to the path C:\MyApp\Web.config is denied. If i change the path of the xdoc.Save to be different from xdoc.Load, then it will be ok. What is your recommandation to solve this problem? If possible, i need to modify the existing xml file(meaning xml file for loading and saving is the same path).
XmlDocument xdoc = new XmlDocument();
xdoc.Load(#"C:\\MyApp\\Web.config");
XmlNode xn = xdoc.SelectSingleNode("//configuration/MyProvider");
XmlElement el = (XmlElement)xn;
el.SetAttribute("defaultProvider", "MyCustomValue");
xdoc.Save(#"C:\\MyApp\\Web.config");
Thanks in advance.
I would expect this to be fine if you have write access to web.config to start with, and if nothing else is using it. (It was certainly fine in a test I just ran.) I suspect it's more likely that another process is already using the file (or the same process but some other code within it), or that you simply don't have write access to the file.

How to open or run unknown file converted into byte[]

I use to store document/file in byte[] in database, and I want user can view/run that file from my application.
You need to know the file extension for the file you're writing, so the OS can run the default program based on the extension. The code would be something like this:
byte[] bytes = GetYourBytesFromDataBase();
string extension = GetYourFileExtension(); //.doc for example
string path = Path.GetTempFileName() + extension;
try
{
using(BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.Create)))
{
writer.Write(yourBytes);
}
// open it with default application based in the
// file extension
Process p = System.Diagnostics.Process.Start(path);
p.Wait();
}
finally
{
//clean the tmp file
File.Delete(path);
}
You will need to store the file extension in the database too. If you don't have the file extension the problem becomes very difficult as you cannot rely on the operating system to work out which program to launch to handle the file.
You can use the following pattern:
Load data from database and save to file using the original file extension.
Start a new System.Diagnostics.Process that points to the saved file path.
As you have saved the file with the original file extension, the OS will look for a program that is registered for the extension to open the file.
As chibacity and Daniel suggest, storing the file extension in the db, and agreed -- storing the file extension, or at least some indicator that tells you the file type, is a good idea.
If these files are of a format of your own creation then you might also want to store information about which version of the file format the data is stored in. During development file formats are prone to changing, and if you don't remember which version you used to store the data then you have a hard job recovering the information.
The same problems are faced in object persistence generally.

Write to Specific line in text file C#

I have a web app that I am developing at work. I need to be able to take input data and append a text file after (x) number of lines.
My web app is using asp.net with c#
Can anyone help me please?
There's no way of "inserting" into a file in general - or of going to a specific line, without reading all the others, unless they're of a fixed size (in bytes).
Normally the approach would be something like:
Start writing a new file
Open the existing file
Copy the first x lines from the old file to the new one
Write the new line
Copy the remaining lines from the old file to the new one
Move the old one to a backup file
Move the new file to the old name
Delete the backup file
(This ensures that at any one point there's at least the old file in some form. You can make it slightly simpler if you just delete the old file and then move the new one into place.)
Don't forget to ensure this is synchronized appropriately - you don't want to have two copies of this algorithm running at the same time...
EDIT: If you've got XML files, then I'd suggest usually just loading it into the DOM (e.g. with LINQ to XML), making the change, and then saving it out again. Don't treat it just like an unstructured text file.
You could potentially make this more efficient using XmlReader and XmlWriter - but you're certainly going to have to read the whole original file and write out the new file. Have you benchmarked simple code and found it too slow? How often are you doing this? How big are the files?
I would suggest finding another strategy, specifically a relational database management system. A text file lives on the file system and does not support concurrent access like a good (read:not Access) database. A web application does support concurrent requests. Once you have more than one user working at the same time, your app will experience IO Exceptions.
OK - Thanks to your help Jon I have figured it out.
FileInfo fi = new FileInfo(Server.MapPath("~/Playlists/" + user + "/" + ListBox1.SelectedItem.Text + ".wpl"));
XmlDocument originalXML = new XmlDocument();
originalXML.Load(fi.FullName);
XmlWriter newXML = XmlWriter.Create(Server.MapPath("~/Playlists/" + user + "/" + ListBox1.SelectedItem.Text + ".wpl"));
XmlNode smil = originalXML.SelectSingleNode("smil/body/seq");
XmlNode media = originalXML.CreateNode(XmlNodeType.Element, "media", null);
XmlAttribute src = originalXML.CreateAttribute("src");
DirectoryInfo di = new DirectoryInfo(Server.MapPath("~" + folder));
foreach (FileInfo file in di.GetFiles("*", SearchOption.AllDirectories))
{
string path = file.FullName;
path = path.Replace(#"F:\Music\Music by Artist", "http://bgab-mor01-n/Music");
path = path.Replace(#"\", "/");
path = path.Replace(",", "");
path = path.Replace("'", "");
path = path.Replace("&", "");
if (file.Extension == ".mp3" || file.Extension == ".wma" || file.Extension == ".MP3")
{
src.Value = path;
media.Attributes.Append(src);
smil.AppendChild(media);
}
}
originalXML.Save(newXML);
newXML.Close();
I really couldn't have done it without you. You are the man. Thanks for everything.

Categories

Resources