Parsing XML file using XMLDocument and moving causes exception - c#

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

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.

Writing a CSV log file

I have a Winforms program that needs to log data points into a .CSV file. It's fairly simple, date/time and a double (the data), and go to the next line.
Here's what I have so far (not working, I get an error saying the file is busy/already open - however, it's empty)
if (!Directory.Exists(SavePath.Text + "\\LOG"))
Directory.CreateDirectory(SavePath.Text + "\\LOG");
string LogFileName = SavePath.Text + "\\LOG\\Seeing-Log-" + TimeNow.ToString("yyyy-MM-dd") + ".csv";
if (!File.Exists(LogFileName))
File.Create(LogFileName);
string LogString = TimeNow.ToString("yyyy-MM-dd-_HH-mm-ss") + "," + FWHM_Value.ToString("F:");
File.AppendAllText(LogFileName, LogString + Environment.NewLine);
It's that last line that generates the error.
Any idea what I am doing wrong?
thanks
Steve
File.Create returns an open FileStream to the file that's just been created. Either change your code to work with FileStream in both the non-existent and existent file cases, or just close the file after creating it:
if (!File.Exists(LogFileName))
File.Create(LogFileName).Close();
But, of course, if you check the documentation for AppendAllText:
Appends the specified stringto the file, creating the file if it does not already exist.
You'll realise that the above two lines are completely redundant anyway and can be removed:
if (!Directory.Exists(SavePath.Text + "\\LOG"))
Directory.CreateDirectory(SavePath.Text + "\\LOG");
string LogString = TimeNow.ToString("yyyy-MM-dd-_HH-mm-ss") + "," + FWHM_Value.ToString("F:");
File.AppendAllText(LogFileName, LogString + Environment.NewLine);
You can even use the free looging tools. Here is one 'log4net'
You can also write the csv file using this. I am assuming currently you are not using logging tool. it will work for you without any code for implementation .
http://element533.blogspot.in/2010/05/writing-to-csv-using-log4net.html
Have a great day!!
Replace
File.Create(LogFileName);
with
File.Create(LogFileName).Close();
see this to create empty file.
The file is locked when you create it. Just update your code to this:
File.Create(LogFileName).Close();

Zip File Entry has custom file extension. C# claims it cannot open

Solution Found.
Thanks to everyone helping me, I found out what the root problem was. The .trl file had nothing to do with it. It was the path being created wrong. I was doing "TRLR" + Path, when it should have been "TRLR" + fileName. This was a stupid error on my part, and I apologize for wasting your time, but I appreciate the help!
I have a zip file given to us by a 3rd party. In this zip files are custom files. These are just text files with a different extension, which I assume is just to frustrate me.
I'm trying to open this files in my C# application, but it keeps throwing the error that the format is not supported.
Since these are just text files, I feel there must be some way for this to happen.
If anyone has any ideas, please let me know.
Code:
using (ZipArchive archive = ZipFile.OpenRead(_trailerName))
{
ZipArchiveEntry entry = archive.GetEntry(tableChanged + ".trl");
Stream ms = entry.Open(); //Here is what's causing the issue.
StreamReader reader = new StreamReader(ms);
string allLinesRead = reader.ReadToEnd();
string[] everyCell = allLinesRead.Split('|');
int numRecords = Convert.ToInt32(everyCell[1]);
int numChanged = getRecordNum(tableChanged);
Console.Write(numRecords + "/" + numChanged + " - " + tableChanged);
if (numChanged != numRecords)
{
_errorMessage += "Records updated do not match trailer. (" + numRecords + "/" + numChanged + ") Please check database. Table affected: " + tableChanged + Environment.NewLine;
}
}
Error:
The given path's format is not supported.
I know this is specific, but I need advice on what steps I can take to resolve this.
Thanks.
The native zip functionality of .NET is frequently lacking in terms of the ability to handle and modify zip files created by applications other than the windows zip tool. While the "zip" file is standardized, you still see a decent amount of variation on file headers and attributes.
I would suggest you look into DotNetZip (Ionic), which is a third party library that has very robust capabilities in terms of creating and opening zip files. I've found it to be much more forgiving and capable than the basic functionality that .NET gives you, and the code to open a zip is extremely similar to what you have.

problem while writing data into xml, when event occured

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.

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