3

Can anyone explain how to read first 10 lines from the text file in LINQ.

Code using StreamReader:

using (var reader = new StreamReader(fileName))
{
    string ListLines = "";
    for (int i = 0; i < 10; i++)
    {
        ListLines[i] = reader.ReadLine();
    }
}
return ListLines;
tshepang
  • 12,111
  • 21
  • 91
  • 136
Rushabh Shah
  • 277
  • 4
  • 10
  • 21
  • Have you tried anything yet? Post it up so we can take a look and help you. – Abe Miessler Aug 22 '12 at 16:55
  • 4
    What have you tried? (It's very simple, but it sounds like it may well be homework, and you haven't given any indication of putting effort in. If you give more information about what you've tried, I'm sure you'll get helpful answers.) – Jon Skeet Aug 22 '12 at 16:55
  • i tried using C# - StreamReader but I want to know whether it is possible with LINQ or not. – Rushabh Shah Aug 22 '12 at 16:56
  • This might help; http://stackoverflow.com/questions/1271225/c-sharp-reading-a-file-line-by-line – Dane Balia Aug 22 '12 at 16:58

4 Answers4

10

You can use:

var lines = File.ReadLines(path).Take(10));

By using ReadLines, rather than ReadAllLines you will stream data from the file, rather than reading the entire thing into memory. If you are still on C# 3.5, not 4 (when ReadLines was added) you can use the below implementation:

public static IEnumerable<string> ReadLines(string filename)
{
    using (TextReader tr = new StreamReader(filename))
    {
        string nextLine = tr.ReadLine();

        while (nextLine != null)
        {
            yield return nextLine;
            nextLine = tr.ReadLine();
        }
    }
}
Servy
  • 202,030
  • 26
  • 332
  • 449
  • Doesn't File.ReadLines() (and your manual implementation) still read every line in the file? This doesn't seem to address the performance concerns. – itsme86 Aug 22 '12 at 17:52
  • @itsme86 No, it doesn't read every line in the file. It defers execution, and because of the `Take` call it will only end up reading the first 10 lines. One easy way to show this is to use my method, and add a `Console.WriteLine` after every read line and see how many lines end up being printed. – Servy Aug 22 '12 at 17:54
  • Ahh, that makes sense now. +1. – itsme86 Aug 22 '12 at 17:55
  • But is it really that clever to acquire a resource for an undefined amount of time? If the system acquires a read-lock for that file no one is able to write to that file as long as the enumerator is alive. And that's possibly a long time. Is this correct? – Johannes Egger Aug 22 '12 at 20:10
  • 1
    @Jasd You can just `ToArray` or `ToList` it right away to read in all of the data. For just 10 lines, that would be desirable. Alternatively it's probable that you would put the whole thing into a `foreach` loop. That would mean that no more than one line needs to be in memory at the same time. If you are processing a very large amount of data, that could be a requirement. If you do that though, you are correct that the file will be locked while the processing takes place. – Servy Aug 22 '12 at 20:14
  • +1 You've touched on the delayed-execution nature of your `IEnumerable` without mentioning another interesting aspect. If you iterate the IEnumerable multiple times, it will re-open and walk the file lines each time; depending on your needs could be either really desirable (e.g., tailing a log file) or really annoying. Nice answer. – devgeezer Aug 23 '12 at 04:36
6

Your code is already optimal to achieve the goal:

var list = new List<string>();
using (var reader = new StreamReader(fileName))
{
    for (int i = 0; i < 10; i++)
    {
        list.Add(reader.ReadLine());
    }
}
return list;

or

using (var reader = new StreamReader(fileName))
{
    for (int i = 0; i < 10; i++)
    {
        yield return reader.ReadLine();
    }
}

or

var r = File.ReadLines(fileName)
            .Take(10)   // limit to first 10
            .ToArray(); // materialize, if needed
Ellis
  • 173
  • 13
abatishchev
  • 98,240
  • 88
  • 296
  • 433
  • public static IEnumerable GetLine(string fileName) { var lines = File.ReadAllLines(fileName).Take(10); return lines; } // this is function which i am trying to call but it doesn't read any line – Rushabh Shah Aug 22 '12 at 17:09
  • @RushabhShah: Call `ToArray()` then – abatishchev Aug 22 '12 at 17:12
5

LINQ style:

using (var textReader = File.OpenText(fileName))
{
    return Enumerable.Range(1, 10).Select(i => textReader.ReadLine());
}
Mo Patel
  • 2,321
  • 4
  • 22
  • 37
cuongle
  • 74,024
  • 28
  • 151
  • 206
  • Interesting. Clever way of preserving performance by avoiding having to read the entire file. – itsme86 Aug 22 '12 at 17:14
  • Error-checking is important, in case the file doesn't contain 10 lines. – Johannes Egger Aug 22 '12 at 17:16
  • @Jasd: agree, it should be, just idea to get it by linq – cuongle Aug 22 '12 at 17:17
  • @abatishchev: Nope, it is still simple and get better performance than Take(10) when having to load all lines into memory, think about of big text file – cuongle Aug 22 '12 at 17:25
  • `Take` is fine as long as you are taking from something that defers reading of the file as long as possible, such as `ReadLines`. – Servy Aug 22 '12 at 17:27
  • This code will result in an exception if there are less than 10 lines, rather than just returning as many as are there. You also are deferring the file reading until you are outside of the `using` block, so the file will be closed by the first time you try to read a line. – Servy Aug 22 '12 at 17:31
  • @CuongLe Who said anything about calling `ReadAllLines`? I know I didn't, and I don't see it being referred to by anyone else in the comments to your answer here. I specifically mentioned `ReadLines`, which properly defers execution. – Servy Aug 22 '12 at 17:33
-1

May you interest this mix :)

using (var reader = new StreamReader(filename))
{
    return (from p in Enumerable.Range(0, 10) select reader.ReadLine()).ToList();
}
Mo Patel
  • 2,321
  • 4
  • 22
  • 37
purplesoft
  • 516
  • 2
  • 10