Reputation: 943
I want to read a .txt file in C# but I will not read all the lines at the same time. For example, consider 500 lines of text file. I want a function to run 25 times and read 20 consecutive lines each time. In the first call of function, lines from 1 to 20 will be read, and second time it is called, 21-40 will be read.
Below simple code does this in c++ but I don't know how to achieve it in C#:
string readLines(ifstream& i)
{
string totalLine="", line = "";
for(int i = 0; i < 20; i++){
getline(i, line);
totalLine += line;
}
return totalLine;
}
int main()
{
// ...
ifstream in;
in.open(filename.c_str());
while(true){
string next20 = readLines(in);
// so something with 20 lines.
}
// ...
}
Upvotes: 1
Views: 549
Reputation: 161
If are trying to call LineRead()
the least number times possible and you want minimum memory usage you could first index the lines in your file:
- Parse the file one time and Index the position of each line in the
FileStream
.- Call ReadLine() only at the desired location.
eg:
// Parse the file
var indexes = new List<long>();
using (var fs = File.OpenRead("text.txt"))
{
indexes.Add(fs.Position);
int chr;
while ((chr = fs.ReadByte()) != -1)
{
if (chr == '\n')
{
indexes.Add(fs.Position);
}
}
}
int minLine = 21;
int maxLine = 40;
// Read the line
using (var fs = File.OpenRead("text.txt"))
{
for(int i = minLine ; i <= maxLine ; i++)
{
fs.Position = indexes[ i ];
using (var sr = new StreamReader(fs))
Console.WriteLine(sr.ReadLine());
}
Cheers !
Upvotes: 2
Reputation: 109852
You could write a Batch() method like so:
public static IEnumerable<string> Batch(IEnumerable<string> input, int batchSize)
{
int n = 0;
var block = new StringBuilder();
foreach (var line in input)
{
block.AppendLine(line);
if (++n != batchSize)
continue;
yield return block.ToString();
block.Clear();
n = 0;
}
if (n != 0)
yield return block.ToString();
}
And call it like this:
string filename = "<Your filename goes here>";
var batches = Batch(File.ReadLines(filename), 20);
foreach (var block in batches)
{
Console.Write(block);
Console.WriteLine("------------------------");
}
Upvotes: 1
Reputation: 120528
Oops. GroupBy does not evaluate lazily, so this will greedily consume whole file
var twentyLineGroups =
File.ReadLines(somePath)
.Select((line, index) => new {line, index})
.GroupBy(x => x.index / 20)
.Select(g => g.Select(x => x.line));
foreach(IEnumerable<string> twentyLineGroup in twentyLineGroups)
{
foreach(string line in twentyLineGroup)
{
//tada!
}
}
Upvotes: 0
Reputation: 1503799
There are various options here, but one simple approach would be:
using (var reader = File.OpenText("file.txt"))
{
for (int i = 0; i < 25; i++)
{
HandleLines(reader);
}
}
...
private void HandleLines(TextReader reader)
{
for (int i = 0; i < 20; i++)
{
string line = reader.ReadLine();
if (line != null) // Handle the file ending early
{
// Process the line
}
}
}
Upvotes: 3