Append to the second to last line in a text file - c#

So I'm making a program to type what's in my clipboard into a text file, I plan on later transporting this information into an AHK script, but I want to do this all in one program, so if possible it will append to the .ahk file, but instead of it appending to the very last line, I need it to append to the line before return, which is the final line of the file.
Send ::redeem N4E2vzCEp {enter}
Sleep 1000
return
That's the end of the file, if possible I want my program to do something like:
string pasted = Clipboard.GetText();
sw.WriteLine.SecondLastLine("Send ::redeem " + pasted + " {enter}");
sw.WriteLine.SecondLastLine("Sleep 1000"); //Fully aware that secondlastline is not a valid command
But I don't know what the proper way of actually coding this would be.
Current code:
private void paste_Click(object sender, EventArgs e)
{
string path = #"c:\users\john\desktop\auths.txt";
using (StreamWriter sw = File.AppendText(path))
{
string pasted = Clipboard.GetText();
sw.WriteLine("Send ::redeem " + pasted + " {enter}");
sw.WriteLine("Sleep 1000");
}
}

What you can do is reading all lines into a List and then insert the new line at a specific position and write the lines back to the file.
List<string> lines = File.ReadAllLines("your file").ToList();
lines.Insert(lines.Count - 2, "new line");
File.WriteAllLines("your file", lines);

Related

How to write text between certain lines using C# [duplicate]

This question already has answers here:
Adding a Line to the Middle of a File with .NET
(6 answers)
Closed 1 year ago.
I'd just like to start by saying the I am extremely new to C# and coding in general so please excuse the newbie mistakes.
I have a text document that looks something like this (inserted manually)
[VIDEO]
[!VIDEO]
And I want to be able to write some text in between these 2 "tags" without erasing them.
The current code I have to write things in the document is:
private void ReadVideoFiles()
{
string[] files =Directory.GetFiles(#"Z:\APP_LANX\VIDEOS", "*.mp4"); //Goes to the specific location of the file and gets the whole location
videoID = 0;
for (int i = 0; i < files.Length; i++)
{
videoID++;
files[i] = videoID.ToString() + ": " + files[i]; //changes the previous string so that it now contains the ID and the location
}
foreach (string file in files)
{
sw.WriteLine(file); //Uses the StreamWriter, declared previously
}
sw.Close();
}
But as you can imagine this just fully replaces everything in the document and adds the code, and the result is something like this:
1: Z:\APP_LANX\VIDEOS\vid1.mp4
2: Z:\APP_LANX\VIDEOS\vid2.mp4
3: Z:\APP_LANX\VIDEOS\vid3.mp4
4: Z:\APP_LANX\VIDEOS\vid4.mp4
instead of this
[VIDEO]
1: Z:\APP_LANX\VIDEOS\vid1.mp4
2: Z:\APP_LANX\VIDEOS\vid2.mp4
3: Z:\APP_LANX\VIDEOS\vid3.mp4
4: Z:\APP_LANX\VIDEOS\vid4.mp4
[!VIDEO]
Is there any way to check for these tags in specific so that I can write in between? Thank you!
Edit*: Later on I'll be adding new things to this text file, for example after the [!VIDEO] line I'll have other lines with something like EX1: 4 and multiple other lines that shouldn't be overwritten, only the part in between those tags can be changed.
TL:DR - Basically I want to be able to add text between those two tags (overwriting whatever is in between) while the rest of the text file remains unchanged
Assuming that your method ReadVideoFiles is called only, you could do something like this:
private void ReadVideoFiles()
{
string[] files =Directory.GetFiles(#"Z:\APP_LANX\VIDEOS", "*.mp4"); //Goes to the specific location of the file and gets the whole location
videoID = 0;
for (int i = 0; i < files.Length; i++)
{
videoID++;
files[i] = videoID.ToString() + ": " + files[i]; //changes the previous string so that it now contains the ID and the location
}
// Add header to file
sw.WriteLine($"[VIDEO]{Environment.NewLine}{Environment.NewLine}");
foreach (string file in files)
{
sw.WriteLine(file); //Uses the StreamWriter, declared previously
}
// Add footer to file
sw.WriteLine($"{Environment.NewLine}{Environment.NewLine}[!VIDEO]");
sw.Close();
}
Instead of inserting your input between the "tags", this code produces the complete file from scratch including the tags.
Maybe this is already sufficient for you? 🤔
If you don't want to spend too much time on it, you can just change :
sw.WriteLine(file);
by :
sw.WriteLine("[VIDEO]\n\n" + file + "\n\n[!VIDEO]");
You'll have the expected result.
You can insert your text at the index of the end tag in your list without overwriting any previous text you had in the file.
using System.IO;
using System.Linq;
endTag = "[!VIDEO]"
foreach (string file in files)
{
sw.Insert(sw.IndexOf(endTag), "text you want to add");
// You can replace "text you want to add" with your file variable
}
sw.Close();

iPad can't read text file

In my Unity3D project I have several text fields. I saved my text in some text files.
When I test my project on the computer everything works fine, and my code reads the text files. But if I upload to my iPad it won't work and the text fields stay empty.
In the image you can see where I have saved my text files.
To read my text files I use the following code:
public Text infoText;
void Update()
{
readTextFile("FileName", "StepNumber")
}
public void readTextFile(string fileName, string stepNumber)
{
StreamReader txt_Reader = new StreamReader("Assets/Resources/Text_Files/" + fileName + ".txt");
while(!txt_Reader.EndOfStream)
{
string txt_String = txt_Reader.ReadLine();
if(txt_String.Contains(stepNumber))
{
string[] separator = { "_" };
string[] strList = txt_String.Split(separator, System.StringSplitOptions.RemoveEmptyEntries);
infoText.text = string.Join("\n", strList.Skip(1));
}
}
}
What do I have to change that my iPad can read from the text files?
EDIT:
My text files looks like this:
Step 1:
* Some Text
* Some Text
Step 2:
* Some Text
* Some Text
* Some Text
Step 3:
* Some Text
Step 4:
* Some Text
So each * should be a new line in my text field. With my old c# code this was no problem, but with
var lines = textFiles.text.Split(new char[] { `*` });
foreach(var line in lines)
{
...
}
i do not know how I can do that, that my text field shows all two lines for step one.
First of all from the Best Practices for the Resources folder
**Don't use it!
Please read the reasons there.
In general for system paths do never use simple string concatenation + "/" +!
Rather use Path.Combine which automatically uses the correct path separators according to the executing platform
Path.Combine(Application.dataPath, "Resources", "Text_Files", fileName + ".txt");
However, you don't/can't simply use a StreamReader to access the Resources folders (See Resources API since it is packed into the build so you have to go through Resources.Load like
// Here you can use / since this is how Unity stores internal paths
// for load you omit the suffix
TextAsset textFile = Resources.Load<TextAsset>("Text_Files/" + filename);
string fileContent = textFile.text;
Or also have a look at Resources.LoadAsync to not block the main thread meanwhile.
BUT
Speaking about blocking the main thread: What you definitely do not want to do is using any of these within Update thus doing heavy FileIO/Loading every frame!
Store the content of that file once as it won't change afterwards anyway!
Depending on your needs you could also simply put your file in any other folder inside the Assets and simply use a TextAsset field directly and drag it into according slot via the Inspector
public TextAsset textFile;
Finally you can then go through the lines one by one using e.g.
var lines = textFile.text.Split(new char[]{'/n'});
foreach(var line in lines)
{
...
}
Note that also that Split is a quite heavy operation since it has to parse every single character in the string and create new substrings so even store these results somewhere in a field of you need them multiple times during runtime!
Typed on smartphone but I hope the idea gets clear
In your case, StreamReader txt_Reader = new StreamReader("Assets/Resources/Text_Files/" + fileName + ".txt"); points to a file on your computer. Assets/Resources/Text_Files/ only exists on your computer.
You need to access a folder that exists on your iPad. It's likely you also didn't save your data to a folder existing on your IPad.
For other devices you could use : Application.persistentDataPath + "/" + fileName
Source: https://docs.unity3d.com/ScriptReference/Application-dataPath.html

C# Save a copy of a text file after replacing values with .Replace

I have a method that i am using to replace values in a txt file.
protected void SendFormData(NameValueCollection formData)
{
string fileName = Server.MapPath("/_TextTemplate/textTemplate.txt");
string emailBody = File.ReadAllText(fileName);
foreach (string val in formData.AllKeys)
{
emailBody = emailBody.Replace("##"+ val +"##", formData[val]);
}
}
I plan on saving a copy of this text file after i have replaced the values. How can give this file a logical name and save a copy of it in my directory?
I did some googleing and File.WriteAllLines keeps popping up.
File.WriteAllLines(#"/_TextTemplate/" + formData[0] + ".txt", formData[0]);
But VS is complaining about that.
File.WriteAllLines
Expects an IEnumerable<string> as an argument. You want
File.WriteAllText(#"/_TextTemplate/" + formData[0] + ".txt", formData[0])

/r after every word

So, I am creaing a "Hangman" game, with a word editor to put your own word in the game. I have a form which opens a text file and displays the content in a multi-line textbox. After that the user can edit the textbox. If you press "save" the content from the textbox will be saved to the text file.
Now, everything works good, the reading and the writing. But now if I want to play my words, its always longer than the word I entered. I found out via debugging that somehow my programm adds "/r" behind every word. For example if I enter "Test" in the wordeditor, the game would use it as "Test/r".
I believe it is an error in the wordeditor so here is the code:
namespace Hangman
{
public partial class WordEditor : Form
{
public WordEditor()
{
InitializeComponent();
using (StreamReader sr = new StreamReader(new FileStream("C:\\Users\\tstadler\\Desktop\\Hangman.txt", FileMode.Open)))
{
string[] Lines = sr.ReadToEnd().Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < Lines.Length; i++)
{
textBox1.Text += Lines[i] + Environment.NewLine;
}
}
}
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
string[] words = textBox1.Text.Split('\n');
FileStream overwrite = new FileStream("C:\\Users\\tstadler\\Desktop\\Hangman.txt", FileMode.Create);
using (StreamWriter file = new StreamWriter(overwrite))
{
for (int i = 0; i < words.Length; i++)
{
file.Write(words[i] + Environment.NewLine);
}
}
MessageBox.Show("Words saved. ");
}
Can anyone tell me if he recognizes the error?
Thanks.
Everywhere you insert new lines you use Environment.NewLine - except for one line:
string[] words = textBox1.Text.Split('\n');
Which results in a string splitted by \n whereas Environment.NewLine consists of \r\n on a Windows system. Thus after the split the \rremains at the end of the string.
To resolve that issue simple replace the line mentioned above with
string[] words = textBox1.Text.Split(new string[] { Environment.NewLine });
Use File.ReadAllLines:
Opens a text file, reads all lines of the file, and then closes the file:
A line is defined as a sequence of characters followed by a carriage return \r, a line feed \n, or a carriage return immediately followed by a line feed.
and File.WriteAllLines:
Creates a new file, write the specified string array to the file, and then closes the file.
sample:
string[] lines = File.ReadAllLines("filePath");
File.WriteAllLines("filePath", textBox.Text.Split(new[] {Environment.NewLine}));
Your solution is almosut correct but very verbose look at this:
File.ReadAllLines;
and
File.WriteAllText;
so your read section would be:
textBox1.Text = string.Join(Environment.NewLine,
File.ReadAllLines(filePath).Where(x=>!string.IsNullOrWhiteSpace(x)));
and write
File.WriteAllText(filePath,textBox1.Text);

C# - Comparing/Replacing Text Using Two .txt Files

I want to take in a certain format of one text file. After the first file is loaded and reformatted, I want to open a second text file and check if the second file has any text matches with the first re-formatted file. Right now I am successfully reformatting the first text file to how I want it. The first (reformatted) text file looks like this:
1 0010 12345 DEF, DEF-0320
1 0020 ABC-00010G ABC-A,1xx,10%,x1x,0603
1 0020A ABC-00010G ABC-A,1xx,10%,x1x,0603
1 0030A ABC-00127G ABC,4.7xx,10%,x1x,0805
.
.
.
I want to know how to take this file (above) and find the second column (0010, 0020, 0020A, 0030A, ...) and compare it/search for it in a second text file. The format for the second text file will look something like this:
10 BARE PCB
20 T C40, C3112
B D5, D45, D48
30 B R25
.
.
.
Once I am able to find the match from the first file (0010, 0020, 0020A, 0030A) with the second file (10, 20, B, 30) I want to grab the lines after the 10, 20, B, 30 and replace the first files 0010, 0020, 0020A, 0030A with them. Also, if the number from the first one does not end with an "A" (ie, 0010) I want to put a "T" at the end of the new file. However, if it does end with an "A" (ie, 0030A) I want to put a "B" at the end of the file. Also, for every value in the second file that is in the format "C40" (or similar) I want to place on a new line if there is multiple (seperated by a ",") and copy the same information from the above line. This meaning it would look like this:
1 AAAA BCD 12345 DEF, DEF-0320 T
1 C40 ABC-00010G ABC-A,1xx,10%,x1x,0603 T
1 C3112 ABC-00010G ABC-A,1xx,10%,x1x,0603 T
1 D5 ABC-00010G ABC-A,1xx,20%,x1x,0603 B
1 D45 ABC-00010G ABC-A,1xx,20%,x1x,0603 B
1 D48 ABC-00010G ABC-A,1xx,20%,x1x,0603 B
1 R25 ABC-00127G ABC,4.7xx,100%,x1x,0805 B
General basis of my code:
Open button: Opens a txt file.
Save button: Saves the new formatted text file where ever I want to save it to.
Clear button: Clears the text in all of the rich text boxes I use.
OpenRefs button: Opens the second txt file used to compare with the first file.**
**I am also trying to get this button to output the final formatting of the text into the final rich text box.
Here is my current code.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using System.Text.RegularExpressions;
namespace Formatter
{
public partial class Form : Form
{
// Create a OpenFileDialog to request a path and file name to open.
OpenFileDialog openFile = new OpenFileDialog();
OpenFileDialog openRefs = new OpenFileDialog();
public Form()
{
InitializeComponent();
}
private void openButton_Click(object sender, EventArgs e)
{
// Initialize the OpenFileDialog to specify the .txt extension as well as
// its intial directory for the file.
openFile.DefaultExt = "*.txt";
openFile.Filter = ".txt Files|*.txt";
openFile.InitialDirectory = "C:\\";
openFile.RestoreDirectory = true;
try
{
// Open the contents of the file into the originalTextRichTextBox.
if (openFile.ShowDialog() == DialogResult.OK && openFile.FileName.Length > 0)
originalTextRichTextBox.LoadFile(openFile.FileName, RichTextBoxStreamType.PlainText);
// Throws a FileNotFoundException otherwise.
else
throw new FileNotFoundException();
// Resets the formattedTextRichTextBox so multiple files aren't loaded on top of eachother.
formattedTextRichTextBox.ResetText();
foreach (string line in File.ReadAllLines(openFile.FileName))
{
// Uses regular expressions to find a line that has, digit(s), space(s), digit(s) + letter(s),
// space(s), digit(s), space(s), any character (up to 25 times).
Match theMatch = Regex.Match(line, #"^[\.*\d]+\s+[\d\w]+\s+[\d\-\w*]+\s+.{25}");
if (theMatch.Success)
{
// Stores the matched value in string output.
string output = theMatch.Value;
// Sets the formattedTextRichTextBox to the string output.
formattedTextRichTextBox.AppendText(output);
formattedTextRichTextBox.AppendText("\n");
}
}
}
// Catches an exception if the file was not opened.
catch (Exception)
{
MessageBox.Show("There was not a specified file path.", "Path Not Found Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
private void saveButton_Click(object sender, EventArgs e)
{
// Create a SaveFileDialog to request a path and file name to save.
SaveFileDialog saveFile = new SaveFileDialog();
// Initialize the SaveFileDialog to specify the .txt extension for the file.
saveFile.DefaultExt = "*.txt";
saveFile.Filter = ".txt Files|*.txt";
saveFile.InitialDirectory = "C:\\";
saveFile.RestoreDirectory = true;
try
{
// Save the contents of the formattedTextRichTextBox into the file.
if (saveFile.ShowDialog() == DialogResult.OK && saveFile.FileName.Length > 0)
formattedTextRichTextBox.SaveFile(saveFile.FileName, RichTextBoxStreamType.PlainText);
// Throws a FileNotFoundException otherwise.
else
throw new FileNotFoundException();
}
// Catches an exception if the file was not saved.
catch (Exception)
{
MessageBox.Show("There was not a specified file path.", "Path Not Found Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
private void clearButton_Click(object sender, EventArgs e)
{
try
{
// Resets the text in all of the boxes.
originalTextRichTextBox.ResetText();
formattedTextRichTextBox.ResetText();
refsTextRichTextBox.ResetText();
finalTextRichTextBox.ResetText();
}
// Catches an exception if the either text box could not be cleared.
catch (Exception)
{
MessageBox.Show("Could not clear the text.", "Clearing Text Box Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
private void openRefsButton_Click(object sender, EventArgs e)
{
// Initialize the OpenFileDialog to specify the .txt extension as well as
// its intial directory for the file.
openRefs.DefaultExt = "*.txt";
openRefs.Filter = ".txt Files|*.txt";
openRefs.InitialDirectory = "C:\\";
openRefs.RestoreDirectory = true;
try
{
// Open the contents of the file into the originalTextRichTextBox.
if (openRefs.ShowDialog() == DialogResult.OK && openRefs.FileName.Length > 0)
refsTextRichTextBox.LoadFile(openRefs.FileName, RichTextBoxStreamType.PlainText);
// Throws a FileNotFoundException otherwise.
else
throw new FileNotFoundException();
// ********************************************
// ********************************************
// ********************************************
// FROM HERE DOWN IS WHERE I NEED THE HELP! :)
// ********************************************
// ********************************************
// ********************************************
string[] refLines = System.IO.File.ReadAllLines(openRefs.FileName);
foreach (string line in refLines)
{
finalTextRichTextBox.AppendText(line + "\n");
}
try
{
using (StreamReader readRefs = new StreamReader(openRefs.FileName))
{
originalTextRichTextBox.ResetText();
List<string> refFileLines = new List<string>();
while (!readRefs.EndOfStream)
{
refFileLines.Add(readRefs.ReadLine());
}
using (StreamReader readFile = new StreamReader(openFile.FileName))
{
List<string> fileLines = new List<string>();
while (!readFile.EndOfStream)
{
fileLines.Add(readFile.ReadLine());
}
}
refFileLines.Contains("");
}
}
catch (Exception)
{
MessageBox.Show("Could not read file.", "Read File Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
// Catches an exception if the file was not opened.
catch (Exception)
{
MessageBox.Show("There was not a specified file path.", "Path Not Found Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
}
}
I am getting a little lost on what to do. I was trying to take in each line and store it in a list of strings and once I had both files (open button and openrefs button) read into two sets of List I was going to use string.contains("some_string") but in the files the numbers could each time I open a different file. I am not sure how I would go about iterating properly though each item in each list to compare the strings (that can be different each 'session'). I was also going to concatinate them together and add the final result into another List and write it to the final rich text box. However, I am getting lost and am pretty new to C#. Any help would be greatly appreciated.
Question: How can I compare these two text files, put them into a list properly, compare the two lists for values that are similar, replace the values in the first file with the following text from the matched values in the second file? If this is confusing, let me know!
Thanks in advance! :)
If your columns are delimited with spaces, or some other character(s), using string.Split to make an array of columns. Pick out the column you want and store it in a SortedList (column is both key and value), checking each time you add to ensure no duplicates are added. Read your second file one line at a time, foreach on SortedList keys, and if string.Contains the key, flag the line as having one of the column values.
I don't really get the formatting of your records because you say you are splitting with a space but your records won't split correctly on that. If your file is a fixed length file then you can use .substring to pull data out. If I am reading your question right I think you are going to want to read each line of the first file and add it the line into a hashset using the second column as a key and then the rest of the line as the value. Then cycle through the second file and for each value in the line find the key it goes with and print the value from the key along with the value of the line you just read. You can then find a spot to add a condition that if the key has an "A" or what not you also print a "T" at the end. I think you should stay away from the regex because performance is generally lacking and I don't think it's what you need here.
string strFileName = DisplayFile("Please Select File 1", ".txt", null);
StreamReader srInput = File.OpenText(strFileName);
Hashtable newHash = new Hashtable();
while(srInput.Peek > -1)
{
string temp = srInput.ReadLine();
string parts = temp.Split('//put delimiter here');
newHash.Add(parts[1]//your key should be your second column value,parts [2]//this is your value);
}
//then read in your second file and test each line to see if it has a match in the first file.
string strFileName2 = DisplayFile("Please Select File 2", ".txt", null);
StreamReader srInput2 = File.OpenText(strFileName);
while(srInput2.Peek > -1)
{
string temp2 = srInput.Readline();
string[] parts2 = temp2.Split('delim');
if(newHash.ContainsKey(parts[whichever is the column you want to check is]))
{
//then print to value to new file or list
//newList.Add(parts[that were checked] + newHash[parts that were checked]);
}
}
something like that will work.

Categories

Resources