C# store file lines into array, then save chosen lines - c#

I am trying to make code, that will basically open desired file, store all lines into array, and then, if line does fulfill condition, line will be save into new text file. When running program, I get error message to line reader, that index is outside of array. Please help, I am new to C#
int NumLines = new StreamReader(OpenFile.FileName).ReadToEnd().Split(new char[] { '\n' }).Length;
StreamReader Data = new StreamReader(OpenFile.FileName);
string[] arr = new string[NumLines];
for (int i = 0; i <= NumLines; i++)
{
StreamWriter File = new StreamWriter("C://Users//Tomas//Desktop//BC//tmp//Data.txt");
arr[i] = Data.ReadLine();

Index should be less than array size:
for (int i = 0; i < NumLines; i++)
^
But you don't need to put lines into array in order to write them to other file. E.g. if you want to write only some lines by condition:
File.WriteAllLines(newFileName, File.ReadLines(OpenFile.FileName).Where(condition));
Where condition is a delegate which checks whether line should be written. E.g. if you want to write only lines which start with "Foo":
.Where(line => line.StartsWith("Foo"))
NOTE: If you want to write all lines to new file without condition, then you simply can copy original file:
File.Copy(OpenFile.FileName, newFileName);
UPDATE: From your comments, it's clear that you need to find line which matches some condition and also write to output 6th and 8th lines after that line. You still can do that without dumping all source file into memory:
private static IEnumerable<string> GetVertexCoordinates(string fileName)
{
var enumerator = File.ReadLines(fileName).GetEnumerator();
while (enumerator.MoveNext())
{
if (enumerator.Current == "VERTEX")
{
yield return enumerator.Current;
for (var i = 0; i < 6; i++) enumerator.MoveNext(); // skip 6 lines
yield return enumerator.Current;
for (var i = 0; i < 2; i++) enumerator.MoveNext(); // skip 2 more lines
yield return enumerator.Current;
}
}
}
And usage is still one-liner
File.WriteAllLines(newFileName, GetVertexCoordinates(OpenFile.FileName));

Try this way:
string[] lines = File.ReadAllLines(filepath);
Then, if you need to compare all lines of this file with some YOUR line, you can do this way:
string targetFilePath = "C://Users//Tomas//Desktop//BC//tmp//Data.txt";
string specificLine = "line, which you try to find";
foreach (var line in lines)
if (line.Equals(specificLine))
File.WriteAllText(targetFilePath, line);

Your code could be shortcutted this way...
/// Disposal of your reader when unused is essential to close your file
using(var reader = new StreamReader(OpenFile.FileName))
{
var lines = reader.ReadToEnd().Split(new char[] { '\n' });
int NumLines = lines.Length;
for (int i = 0; i < NumLines; i++)
{
... do something here
}
}

Related

Skip lines and start read from specific line C# unity

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.

Streamreader reading the same line multiple times C#

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).

Streamreading text files

I have a piece of code that is supposed to streamread this text file:
1.1.1.1.1.1.1.1.1.1.1.1.1.1.1
1.1.1.2.2.2.2.1.1.1.2.2.1.1.1
1.2.2.2.2.2.2.2.2.2.2.2.2.1.1
1.1.2.2.2.2.2.2.2.2.2.2.2.1.1
1.1.2.2.2.2.2.2.2.2.2.2.1.1.1
1.1.1.1.2.2.2.2.2.2.2.2.1.1.1
1.1.1.1.2.2.2.2.2.2.1.1.1.1.1
1.1.1.1.1.1.2.2.2.1.1.1.1.1.1
1.1.1.1.1.1.1.2.1.1.1.1.1.1.1
1.1.1.1.1.1.1.1.1.1.1.1.1.1.1
1.1.1.1.1.1.1.1.1.1.2.2.1.1.1
1.1.1.1.1.1.1.1.1.1.1.1.1.1.1
Everything is going fine, kinda of. My purpose was to rummage through all the characters one by one, then after that's done start on a new line. This is where my little problem occurs, which I've been trying to fix all night.
It reads the first line nicely, but then it doesn't read the second line...
Here is the code:
System.IO.StreamReader file = new System.IO.StreamReader(#"C:\Text\TextFile.txt");
int loadX = 0;
int loadY = 0;
string line;
while (true)
{
if (loadX <= 12)
{
loadX++;
while ((line = file.ReadLine()) != null)
{
System.Threading.Thread.Sleep(500);
string[] entries = line.Split('.');
System.Console.Write(entries[loadX]);
loadY++;
}
}
System.Threading.Thread.Sleep(500);
Console.Write($" Finished {loadX}");
loadX = 0;
}
var lines = File.ReadAllLines(#"C:\Text\TextFile.txt");
var points = lines.SelectMany((l, x) => l.Split('.').Select((s, y) => new {X = x, Y = y, Value = s}));
foreach (var point in points)
{
Console.WriteLine($"({point.X}, {point.Y})={point.Value}");
}
Using a while loop and StremReader seems so silly when you have easier and more readable ways of handling this.
You can easily simplify your code by doing File.ReadAllLines()
//lines will be a string array
var lines = File.ReadAllLines(#"C:\Text\TextFile.txt");
for(int x = 0; x < lines .Length; x++)
{
var cols = lines [x].Split('.');
for(int y = 0; y < cols.Length; x++)
{
//Here you have access to the value, and the x and y position
Console.WriteLine("x: {0}, y: {1} value: {2}", x, y, cols[y]);
}
}
Demo here
If you want to go through every number in this file with X and Y then this is an example how you can do so:
string[] lines = File.ReadAllLines(#"C:\Text\TextFile.txt");
for(int indexY = 0; indexY < lines.Length; indexY++){
string[] lineEntries = lines[indexY].Split('.');
for(int indexX = 0; indexX < lineEntries; indexX++){
// here you have one number by accessing
// it with lineEntries[indexX]
Console.Write(lineEntries[indexX]);
}
Console.WriteLine();
}
You are mistaken to think it is reading the first line. In fact, your current code reads the first value of each line. Due to your input this just happens to be a similar output to what the first line would be, which has lead to your confusion.
Your main loop should be looping through each line, then you can process the line and loop through each value. Which you can then use however you want.
Here is an example:
using(System.IO.StreamReader file = new System.IO.StreamReader(#"C:\Text\TextFile.txt"))
{
int loadX = 0;
int loadY = 0;
string line;
// Loop through each line as you read it.
while ((line = file.ReadLine()) != null)
{
// Split the line to get an array of values.
string[] entries = line.Split('.');
// Loop through each value and process.
for(int i = 0; i < entries.length; i++)
{
string entry = entries[i];
// TODO: Do something with entry.
loadY++;
}
loadX++;
}
}
Obviously in this example loadX and loadY are not being used, but this demonstrates how to correctly increment them so you can use them as needed.
TIP: When using a SteamReader you should ensure you dispose of it correctly, this is best done by including it in a using block.

Extracting the first 10 lines of a file to a string

public void get10FirstLines()
{
StreamReader sr = new StreamReader(path);
String lines = "";
lines = sr.readLine();
}
How can I get the first 10 lines of the file in the string?
Rather than using StreamReader directly, use File.ReadLines which returns an IEnumerable<string>. You can then use LINQ:
var first10Lines = File.ReadLines(path).Take(10).ToList();
The benefit of using File.ReadLines instead of File.ReadAllLines is that it only reads the lines you're interested in, instead of reading the whole file. On the other hand, it's only available in .NET 4+. It's easy to implement with an iterator block if you want it for .NET 3.5 though.
The call to ToList() is there to force the query to be evaluated (i.e. actually read the data) so that it's read exactly once. Without the ToList call, if you tried to iterate over first10Lines more than once, it would read the file more than once (assuming it works at all; I seem to recall that File.ReadLines isn't implemented terribly cleanly in that respect).
If you want the first 10 lines as a single string (e.g. with "\r\n" separating them) then you can use string.Join:
var first10Lines = string.Join("\r\n", File.ReadLines(path).Take(10));
Obviously you can change the separator by changing the first argument in the call.
var lines = File.ReadAllLines(path).Take(10);
You may try to use File.ReadLines. Try this:-
var lines = File.ReadLines(path).Take(10);
In your case try this as you want the first 10 lines as a single string so you may try to use string.Join() like this:
var myStr= string.Join("", File.ReadLines(path).Take(10));
StringBuilder myString = new StringBuilder();
TextReader sr = new StreamReader(path);
for (int i=0; i < 10; i++)
{
myString.Append(sr.ReadLine())
}
String[] lines = new String[10];
for (int i = 0; i < 10; i++)
lines[i] = sr.readLine();
That loops ten times and places the results in a new array.
public void skip10Lines()
{
StringBuilder lines=new StringBuilder();
using(StreamReader sr = new StreamReader(path))
{
String line = "";
int count=0;
while((line= sr.ReadLine())!=null)
{
if(count==10)
break;
lines.Append(line+Environment.NewLine);
count++;
}
}
string myFileData=lines.ToString();
}
OR
public void skip10Lines()
{
int count=0;
List<String> lines=new List<String>();
foreach(var line in File.ReadLines(path))
{
if(count==10)
break;
lines.Add(line);
count++;
}
}
Reason beeing is that the nested operators File.ReadLines(path).Take(10).ToList(); will do the following truly:
string[] lines = File.ReadLines(path); // reads all lines of the file
string[] selectedlines = lines.Take(10); // takes first 10 line s into a new array
List<String> LinesList = selectedlines.ToList();
Especially the first part is cumbersome as it reads the full file into an enumerable of lines. This eats Performance and Memory. The question poster asked specifically for large files.
for this reason, I would rather recommend:
/// <summary>
/// This function loads and returns the first x lines from a file
/// </summary>
/// <param name="path">The path to the file to read</param>
/// <param name="amountOfLines">the number of lines which should be read</param>
/// <param name="encoding">optional value, which specifies the format in which the text file is saved</param>
/// <returns></returns>
public List<string> GetFirstXLines(string path, int amountOfLines, Encoding encoding = null)
{
// if no encoding is set, try the default encoding (File Format)
if (encoding == null) encoding = Encoding.Default;
// create list which will be filled with the lines and returned later
List<string> lines = new List<string>();
// wrap streamreader around so it gets closed+disposed properly later
using (StreamReader reader = new StreamReader(path, encoding))
{
// loop x times to get the first x lines
for (int i = 0; i < amountOfLines; i++)
{
// read the next line
string line = reader.ReadLine();
// if the line is null, we are at the end of file, break out of the loop
if (line == null) break;
// if the line was not null, add it to the lines list
lines.Add(line);
}
}
// return the lines
return lines;
}
In Groovy, a JVM based language, one approach is:
def buf = new StringBuilder()
Iterator iter = new File(path).withReader{
for( int cnt = 0;cnt < 9;cnt++){
buf << it.readLine()
}
}
println buf
Since, there is no 'break' from a closure, the loop is nested within the closure, and thereby the resource handling is taken care of by the Groovy runtime.

C# Split not working

I'm trying to read data from a file, split the data and save to array. The code works fine except for the split. It is returning a NullException.
Any help would be greatly appreciated.
public static void LoadHandData(CurrentHand[] handData, string fileName)
{
string input = ""; //temporary variable to hold one line of data
string[] cardData; //temporary array to hold data split from input
StreamReader readHand = new StreamReader(fileName);
for (int counter = 0; counter < handData.Length; counter++)
{
input = readHand.ReadLine(); //one record
cardData = input.Split(' '); //split record into fields
int index = 0;
handData[counter].cardSuit = Convert.ToChar(cardData[index++]);
handData[counter].cardValue = Convert.ToInt16(cardData[index++]);
}
readHand.Close();
}
As per the comments, you've only got one line of data. But look at your loop:
for (int counter = 0; counter < handData.Length; counter++)
{
input = readHand.ReadLine(); //one record
cardData = input.Split(' '); //split record into fields
int index = 0;
handData[counter].cardSuit = Convert.ToChar(cardData[index++]);
handData[counter].cardValue = Convert.ToInt16(cardData[index++]);
}
That's trying to read one line per hand. On the second iteration, ReadLine will return null, so when you call input.Split() you'll end up with the NullReferenceException you're seeing.
You need to read the line once and split it. Given that you've only got one line of text, you can just use File.ReadAllText to simplify things:
string input = File.ReadAllText(fileName);
string[] cardData = input.Split(' ');
for (int counter = 0; counter < handData.Length; counter++)
{
handData[counter].cardSuit = Convert.ToChar(cardData[counter * 2]);
handData[counter].cardValue = Convert.ToInt16(cardData[counter * 2 + 1]);
}

Categories