How do I move items/values up and down a text file. At the moment my program reads a text file, an uses a while to make sure it stop when there is no more lines to read. I used an if statement to check if counter equals the line of the value I want to move. I am stuck not sure how to continue from here.
_upORDown = 1;
using (StreamReader reader = new StreamReader("textfile.txt"))
{
string line = reader.ReadLine();
int Counter = 1;
while (line != null)
{
if (Counter == _upORDown)
{
//Remove item/replace position
}
Counter++;
}
}
You can read the file in memory, move the line to where you need it, and write the file back. You can use ReadAllLines and WriteAllLines.
This code moves the string at position i up by one line:
if (i == 0) return; // Cannot move up line 0
string path = "c:\\temp\\myfile.txt";
// get the lines
string[] lines = File.ReadAllLines(path);
if (lines.Length <= i) return; // You need at least i lines
// Move the line i up by one
string tmp = lines[i];
lines[i] = lines[i-1];
lines[i-1] = tmp;
// Write the file back
File.WriteAllLines(path, lines);
#dasblinkenlight's answer, using LINQ:
string path = "c:\\temp\\myfile.txt";
var lines = File.ReadAllLines(path);
File.WriteAllLines(
path,
lines.Take(i).Concat(
lines.Skip(i+1)
)
);
This deletes the line at position i (zero-based) and moves the other lines up.
Adding to a new line:
string path = "c:\\temp\\myfile.txt";
var lines = File.ReadAllLines(path);
var newline = "New line here";
File.WriteAllLines(
path,
lines.Take(i).Concat(
new [] {newline}
).Concat(
lines.Skip(i+1)
)
);
Related
I am reading from a file and I am trying to skip first two lines and start reading from the third one. I've checked other questions which were answered but none of them worked on unity for some reason. I get several errors however it should work.
StreamReader reader = new StreamReader(path);
string line = "";
while ((line = reader.ReadLine()) != null)
{
string[] words = line.Split(' ');
string type = words[0];
float x = float.Parse(words[1]);
....
}
If I understand correctly, we can try to use File.ReadAllLines which will return all line of text content from your file text and then start reading on the third line (array start as 0, so that the third line might be contents[2]).
var contents = File.ReadAllLines(path);
for (int i = 2; i < contents.Length; i++)
{
string[] words = contents[i].Split(' ');
string type = words[0];
float x = float.Parse(words[1]);
}
If we know the Encoding of the file we can try to set Encoding to the second parameter in File.ReadAllLines
Similar to D-Shih's solution, is one using File.ReadLines, which returns an IEnumerable<string>:
var lines = File.ReadLines(path);
foreach (string line in lines.Skip(2))
{
string[] words = line.Split(' ');
string type = words[0];
float x = float.Parse(words[1]);
// etc.
}
The benefit of this approach over D-Shih's is that you don't have to read the entire file into memory at once to process it, so this solution is analogous to your existing solution's use of StreamReader.
As a solution for directly fixing your problem, you just need to call ReadLine twice before getting into the loop (to skip the two lines), though I'd argue the solution above is more legible:
using (StreamReader reader = new StreamReader(path))
{
string line = "";
// skip 2 lines
for (int i = 0; i < 2; ++i)
{
reader.ReadLine();
}
// read file normally
while ((line = reader.ReadLine()) != null)
{
string[] words = line.Split(' ');
string type = words[0];
float x = float.Parse(words[1]);
....
}
}
Notice that I've also wrapped the reader in a using, so that the file handle will be closed & disposed of once the loop completes, or in case of an exception being thrown.
So what I want to do its count lines from a text file and count them in 1 line on the console window. This is what I have now, it works but it writes lot of lines to the console and I want it to change the count on 1 line every second.
long lines = 0;
using (StreamReader r = new StreamReader("text.txt"))
{
string line;
while ((line = r.ReadLine()) != null)
{
count++;
Console.Title = "Count: " + lines;
Console.WriteLine(Console.Title);
}
}
You can use File.ReadAllLiness(<filePath>).Count() to get count of lines in text file.
Console.WriteLine(File.ReadAllLiness("text.txt").Count())
Your code is not working because you are printing lines variable which is assigned as 0 at the beginning, but not updated anywhere.
Either try my first solution or use lines variable instead of count in your existing program and print it out of while loop
long lines = 0;
using (StreamReader r = new StreamReader("text.txt"))
{
string line;
while ((line = r.ReadLine()) != null)
{
Console.WriteLine(++lines); //One line solution
}
}
You should take a look at this topic:
How can I update the current line in a C# Windows Console App?
It is possible to update the current line. All you need to add is a logic to only do it once per second.
Maybe something like this:
long lines = 0;
var lastSecond = DateTime.Now.Second;
using (var r = new StreamReader("text.txt"))
{
string line;
while ((line = r.ReadLine()) != null)
{
lines++;
Console.Title = "Count: " + lines;
if(lastSecond != DateTime.Now.Second)
Console.Write("\r{0} ", Console.Title);
lastSecond = DateTime.Now.Second;
}
Console.WriteLine(""); // Create new line at the end
}
There will be nicer ways to update once per second but the main problem seems to be how to update the current console output.
My old method (other than being wrong in general) takes too long to get multiple lines from a file and then store the parameters into a dictionary.
Essentially it's open file, grab every second line one at a time, modify the line then store the data (line pos and the first element of the line (minus) ">") close the file and then repeat.
for (int i = 0; i < linecount - 1; i += 2)
{
string currentline = File.ReadLines
(datafile).Skip(i).Take(1).First();
string[] splitline = currentline.Split(' ');
string filenumber = splitline[0].Trim('>');
} for (int i = 0; i < linecount - 1; i += 2)
You need to read next line inside while loop, otherwise loop body will always analyse first line (that's why there are Dictionary error) and never exist:
while (line != null)
{
// your current code here
line = sr.ReadLine();
}
The issue is that you only ever read the first line of the file. To solve this you need to ensure you call sr.ReadLine() on every iteration through the loop. This would look like:
using (StreamReader sr = File.OpenText(datafile))
{
string line = sr.ReadLine();
while (line != null)
{
count = count ++;
if (count % 2 == 0)
{
string[] splitline = line.Split(' ');
string datanumber = splitline[0].Trim('>');
index.Add(datanumber, count);
}
line = sr.ReadLine();
}
}
This means on each iteration, the value of line will be a new value (from the next line of the file).
string tables = this.webBrowser1.Document.GetElementById("tblProducts").InnerText;
using (StringReader reader = new StringReader(tables))
{
string line;
while ((line = reader.ReadLine()) != null)
{
// Do something with the line
}
}
This is what i did now:
string tables = this.webBrowser1.Document.GetElementById("tblProducts").InnerText;
StreamWriter w = new StreamWriter(#"c:\temp\Table1.txt");
w.WriteLine(tables);
w.Close();
string[] lines = File.ReadAllLines(#"c:\temp\Table1.txt");
for (int i = 0; i < lines.Length; i++)
{
lines[i] = lines[i].Insert(0, "here ADDED TEXT");
}
But instead Insert iwant somehow to Add a new line between line number 1 and line number 2. So if lines contain now 31 lines then in the end it should contain 32 lines a new line between line 1 and line 2. Not to add a new line to the end but between 1 and 2.
I think you're saying that, given text that looks like this:
This is line 1
Second line here
And a third line
What you want is:
This is line 1
<empty line here>
Second line here
And a third line
If so, that should be pretty easy to do:
string tables = this.webBrowser1.Document.GetElementById("tblProducts").InnerText;
var lines = tables.Split(new[]{Environment.NewLine}, StringSplitOptions.None).ToList();
lines.Insert(1, "");
string newText = string.Join(Environment.NewLine, lines);
In a Windows Forms C# app, I have a textbox where users paste log data, and it sorts it. I need to check each line individualy so I split the input by the new line, but if there are a lot of lines, greater than 100,000 or so, it throws a OutOfMemoryException.
My code looks like this:
StringSplitOptions splitOptions = new StringSplitOptions();
if(removeEmptyLines_CB.Checked)
splitOptions = StringSplitOptions.RemoveEmptyEntries;
else
splitOptions = StringSplitOptions.None;
List<string> outputLines = new List<string>();
foreach(string line in input_TB.Text.Split(new string[] { "\r\n", "\n" }, splitOptions))
{
if(line.Contains(inputCompare_TB.Text))
outputLines.Add(line);
}
output_TB.Text = string.Join(Environment.NewLine, outputLines);
The problem comes from when I split the textbox text by line, here input_TB.Text.Split(new string[] { "\r\n", "\n" }
Is there a better way to do this? I've thought about taking the first X amount of text, truncating at a new line and repeat until everything has been read, but this seems tedious. Or is there a way to allocate more memory for it?
Thanks,
Garrett
Update
Thanks to Attila, I came up with this and it seems to work. Thanks
StringReader reader = new StringReader(input_TB.Text);
string line;
while((line = reader.ReadLine()) != null)
{
if(line.Contains(inputCompare_TB.Text))
outputLines.Add(line);
}
output_TB.Text = string.Join(Environment.NewLine, outputLines);
The better way to do this would be to extract and process one line at a time, and use a StringBuilder to create the result:
StringBuilder outputTxt = new StringBuilder();
string txt = input_TB.Text;
int txtIndex = 0;
while (txtIndex < txt.Length) {
int startLineIndex = txtIndex;
GetMore:
while (txtIndex < txt.Length && txt[txtIndex] != '\r' && txt[txtIndex] != '\n')) {
txtIndex++;
}
if (txtIndex < txt.Length && txt[txtIndex] == '\r' && (txtIndex == txt.Length-1 || txt[txtIndex+1] != '\n') {
txtIndex++;
goto GetMore;
}
string line = txt.Substring(startLineIndex, txtIndex-startLineIndex);
if (line.Contains(inputCompare_TB.Text)) {
if (outputTxt.Length > 0)
outputTxt.Append(Environment.NewLine);
outputTxt.Append(line);
}
txtIndex++;
}
output_TB.Text = outputTxt.ToString();
Pre-emptive comment: someone will object to the goto - but it is what's needed here, the alternatives are much more complex (reg exp for example), or fake the goto with another loop and continue or break
Using a StringReader to split the lines is a much cleaner solution, but it does not handle both \r\n and \n as a new line:
StringReader reader = new StringReader(input_TB.Text);
StringBuilder outputTxt = new StringBuilder();
string compareTxt = inputCompare_TB.Text;
string line;
while((line = reader.ReadLine()) != null) {
if (line.Contains(compareTxt)) {
if (outputTxt.Length > 0)
outputTxt.Append(Environment.NewLine);
outputTxt.Append(line);
}
}
output_TB.Text = outputTxt.ToString();
Split will have to duplicate the memory need of the original text, plus overhead of string objects for each line. If this causes memory issues, a reliable way of processing the input is to parse one line at a time.
I guess the only way to do this on large text files is to open the file manually and use a StreamReader. Here is an example how to do this.
You can avoid creating strings for all lines and the array by creating the string for each line one at a time:
var eol = new[] { '\r', '\n' };
var pos = 0;
while (pos < input.Length)
{
var i = input.IndexOfAny(eol, pos);
if (i < 0)
{
i = input.Length;
}
if (i != pos)
{
var line = input.Substring(pos, i - pos);
// process line
}
pos = i + 1;
}
On other hand, In this article say that the point is that "split" method is implemented poorly. Read it, and make your conclusions.
Like Attila said, you have to parse line by line.