Write to Specific line in text file C# - 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.

Related

Check if xml exists in a directory and read it

Hello everyone I'm new to c#. I want to read an xml file if it exists in a directory. 1) How can I read it? 2) If there are multiple xml files how to read those at the same time?
XmlTextReader xtr = new XmlTextReader(path)
string pathD = #"H:\UsersDirectory";
DirectoryInfo di = new DirectoryInfo(path);
FileInfo[] TXTFiles = di.GetFiles("*.xml");
if (TXTFiles.Length != 0)
{
//how can I read the file?
}
If you know the name of the file, you can use:
File.Exists("YourPath");
to check if the File exists. If not, you can use:
Directory.GetFiles("ContainingDirectory");
to get a list of all files in a directory, and then loop through them, checking if they end with .xml, to find your file.
As for reading the content of the file, you can use
File.ReadAllText("FilePath");
to read the content of your XML-File. For multiple files, you can obviously just call this function multiple times, once for every file.
If you want to edit XML too, I'd like to direct you towards XPathNavigator: https://learn.microsoft.com/en-us/troubleshoot/developer/visualstudio/csharp/language-compilers/xml-xpathnavigator

.NET Core 2.2 Razor Page Code Behind Creates Text File, But Fails to Write Simple Line To File

Not sure what I am doing wrong. I can create a text file named using Now date and time. My writing to the file fails. If I don't put ".Close()" at the end of the CreateText, it says the file is open by another process when trying to write. With the ".Close()" there are no errors but it doesn't write.
var newFileName = "logs\\" + DateTime.Now.ToString().Replace("/","_").Replace(":","-").Replace(" ","__") + ".txt";
var webRootPath = _environment.WebRootPath;
var dataPath = Path.Combine(webRootPath, newFileName);
System.IO.File.CreateText(dataPath).Close();
System.IO.File.AppendText(dataPath).WriteLine("this is before save");
Just use this:
//System.IO.File.CreateText(dataPath).Close();
System.IO.File.AppendText(dataPath).WriteLine("this is before save");
CreateText() will create a new empty file each time.
AppendText() will create the file if necessary.
But you are leaking file handles here. Appendtext returns a TextWriter that needs to be closed.
Instead of fixing that, consider using a reliable logging packages.

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.

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.

Categories

Resources