views:

158

answers:

7

I'm trying to read in a text file in a c# application, but I don't want to read the first two lines, or the last line. There's 8 lines in the file, so effectivly I just want to read in lines, 3, 4, 5, 6 and 7. Is there any way to do this?

example file

USE [Shelley's Other Database]
CREATE TABLE db.exmpcustomers(
fName varchar(100) NULL,
lName varchar(100) NULL,
dateOfBirth date NULL,
houseNumber int NULL,
streetName varchar(100) NULL
) ON [PRIMARY]

EDIT

Okay, so, I've implemented Callum Rogers answer into my code and for some reason it works with my edited text file (I created a text file with the lines I didn't want to use omitted) and it does exactly what it should, but whenever I try it with the original text file (above) it throws an exception. I display this information in a DataGrid and I think that's where the exception is being thrown.

Any ideas?

+2  A: 

If you have a TextReader object wrapping the filestream you could just call ReadLine() two times.

StreamReader inherits from TextReader, which is abstract.

Non-fool proof example:

using (var fs = new FileStream("blah", FileMode.Open))
using (var reader = new StreamReader(fs))
{
    reader.ReadLine();
    reader.ReadLine();

    // Do stuff.
}
Skurmedel
This dosen't ignore the last line....
AidanO
Let's say I left that out as an excercise :)
Skurmedel
+8  A: 

Why not just use File.ReadAllLines() and then remove the first 2 lines and the last line? With such a small file speed differences will not be noticeable.

string[] allLines = File.ReadAllLines("file.ext");
string[] linesWanted = new string[allLines.Length-3];
Array.Copy(allLines, 2, linesWanted, 0, allLines.Length-3);
Callum Rogers
+1 Simple solution.
Skurmedel
Technically, this does read all lines.
Caspar Kleijne
@Caspar: I don't think it is possible to not read all the lines unless you know the byte index of where the third line and last line start. This is because you have to scan the file until you find the first 2 `\n\r?` before you can exclude all data before it and similarly for the last line you have to find the linebreak for the penultimate line.
Callum Rogers
@Downvoter: Why did you downvote? What is your criticism of my answer?
Callum Rogers
+1 Makes the most sense, is easy to implement, managed properly - probably uses least memory as well
Joel Etherton
+1 Elegant solution
Basiclife
@Joel Uses most memory. Reads entire file into an array, then allocates *another* array to hold most of the first...
Andy Johnson
@Callum Rogers: Thanks so much for your answer! I want to use this code, but I'm fairly new to the C# language, and I'm finding a bit difficult implementing into my existing code, as I already do a lot of 'stuff' with the file already (I created a file without the lines I didn't want, for the purposes of carrying on with my application). I'm currently using StreamReader to read in my file. Will I need to change my code completely?
New Start
@Shelley: no just remove the `StreamReader` (I assume you are only reading it in like `using(StreamReader sr = new StreamReader("")) lines.Add(sr.ReadLine());`) and replace with the code above. Then each line is a string inside that array, so to access line 3 you would do `linesWanted[2]` to get or set that line. If you were using a `List`, you can change the array into a list by doing `linesWanted.ToList()`. Ask if you need more help, or post the code and I will look at it :)
Callum Rogers
I think I might post my code.. how do I do that?
New Start
@Shelley: I would paste it into http://pastebin.com/, select C# and put the link in a comment here.
Callum Rogers
@Callum Rogers: http://pastebin.com/embed_js.php?i=8FKJuEuy
New Start
@Callum Rogers: thought I'd let you see this as well; it's the code that calls the method. I'm assuming it will be affected if I change the method. http://pastebin.com/embed_js.php?i=TbXLDJQB
New Start
@Shelley: Here is the code I think you want: http://pastebin.com/nAjtuyrv. There are 2 versions which do exactly the same thing, the second is more elegant but you may not have learn't enough C# to understand it. Choose one but make sure you understand what's going on with the code.
Callum Rogers
@Callum Rogers: Thank you so much, you seem to be pretty advanced in comparison to me! I've tried it out, it seems to work with the file that I currently used (with the unwanted lines ommited), but when I try the original, it throws an exception. Could it have anything to do with the code that calls the method? And btw, totally off subject, but went onto your website and saw some of your programs and code - wow!
New Start
@Shelley: Which line is the exception thrown at and what is it? What are you expecting `FormatRow formatFileDetails = Shared.ReadFormatFile(formatDialog.FileName)[0];` to do? Do you expect to read the first row of the original file or the one with the lines lines omitted?
Callum Rogers
@Callum Rogers: The file is chosen using an OpenFileDialog, so it's whichever file I choose. And yeah, it reads the first line of the file (this is just for display purposes, I tried commenting out the display code and it still throws). I think it's throwing when I try to display it in my DataGrid.. But I'm just confused because it works and displays in the DataGrid when I choose the file with the lines omitted..
New Start
@Shelley: I don't think I can tell you then, without seeing your whole code. I have to go and finish cutting down a tree now :)
Callum Rogers
A: 

You can do this:

var valid = new int[] { 3, 4, 5, 6, 7 };
var lines = File.ReadAllLines("file.txt").
    Where((line, index) => valid.Contains(index + 1));

Or the opposite:

var invalid = new int[] { 1, 2, 8 };
var lines = File.ReadAllLines("file.txt").
    Where((line, index) => !invalid.Contains(index + 1));

If you're looking for a general way to remove the last and the first 2, you can use this:

var allLines = File.ReadAllLines("file.txt");
var lines = allLines
  .Take(allLines.Length - 1)
  .Skip(2);

But from your example it seems that you're better off looking for the string pattern that you want to read from the file. Try using regexes.

Jordão
+8  A: 

Why do you want to ignore exactly the first two and the last line?

Depending on what your file looks like you might want to analyze the line, e.g. look at the first character whether it is a comment sign, or ignore everything until you find the first empty line, etc.

Sometimes, hardcoding "magic" numbers isn't such a good idea. What if the file format needs to be changed to contain 3 header lines?

As the other answers demonstrate: Nothing keeps you from doing what you ever want with a line you have read, so of course, you can ignore it, too.

Edit, now that you've provided an example of your file: For your case I'd definitely not use the hardcoded numbers approach. What if some day the SQL statement should contain another field, or if it appears on one instead of 8 lines?

My suggestion: Read in the whole string at once, then analyze it. Safest way would be to use a grammar, but if you presume the SQL statement is never going to be more complicated, you can use a regular expression (still much better than using line numbers etc.):

string content = File.ReadAllText(filename);
Regex r = new Regex(@"CREATE TABLE [^\(]+\((.*)\) ON");
string whatYouWant = r.Match(content).Groups[0].Value;
chiccodoro
The why is very important here I think, a bit more information about what you're trying to do could lead to better solutions being offered
AidanO
GxG
I've posted an exmaple of the file I'm trying to read in..
New Start
If you look at his edited question, it would be a bad idea to delimit parts of that code with separators. And doing something like this to SQL rather than just running it does seem like it could be massively dodgy.
Callum Rogers
No in that case a delimiter isn't a great idea, but it's still possible to use a regex e.g. I've edited my answer accordingly.
chiccodoro
+1 Regex is definitely the best approach.
Filburt
Good idea with the regex.
Callum Rogers
A: 
string filepath = @"C:\whatever.txt";
using (StreamReader rdr = new StreamReader(filepath))
{
    rdr.ReadLine();  // ignore 1st line
    rdr.ReadLine();  // ignore 2nd line
    string fileContents = "";
    while (true)
    {
        string line = rdr.ReadLine();
        if (rdr.EndOfStream)
            break;  // finish without processing last line
        fileContents += line + @"\r\n";
    }
    Console.WriteLine(fileContents);
}
Andy Johnson
Just to make it system independent, you could use `Environment.NewLine` instead of `\r\n`.
Callum Rogers
@Callum. Thanks for reminding me!
Andy Johnson
+10  A: 

The Answer by Rogers is good, I am just providing aother way of doing this. Try this,

List<string> list = new List<string>();
        using (StreamReader reader = new StreamReader(FilePath))
        {
            string text = "";
            while ((text = reader.ReadLine()) != null)
            {
                list.Add(text);
            }
            list.RemoveAt(0);
            list.RemoveAt(0);
        }

Hope this helps

sumit_programmer
A: 

How about a general solution?

To me, the first step is to enumerate over the lines of a file (already provided by ReadAllLines, but that has a performance cost due to populating an entire string[] array; there's also ReadLines, but that's only available as of .NET 4.0).

Implementing this is pretty trivial:

public static IEnumerable<string> EnumerateLines(this FileInfo file)
{
    using (var reader = file.OpenText())
    {
        while (!reader.EndOfStream)
        {
            yield return reader.ReadLine();
        }
    }
}

The next step is to simply skip the first two lines of this enumerable sequence. This is straightforward using the Skip extension method.

The last step is to ignore the last line of the enumerable sequence. Here's one way you could implement this:

public static IEnumerable<T> IgnoreLast<T>(this IEnumerable<T> source, int ignoreCount)
{
    if (ignoreCount < 0)
    {
        throw new ArgumentOutOfRangeException("ignoreCount");
    }

    var buffer = new Queue<T>();
    foreach (T value in source)
    {
        if (buffer.Count < ignoreCount)
        {
            buffer.Enqueue(value);
            continue;
        }

        T buffered = buffer.Dequeue();

        buffer.Enqueue(value);

        yield return buffered;
    }
}

OK, then. Putting it all together, we have:

var file = new FileInfo(@"path\to\file.txt");
var lines = file.EnumerateLines().Skip(2).IgnoreLast(1);

Test input (contents of file):

This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
This is line number 5.
This is line number 6.
This is line number 7.
This is line number 8.
This is line number 9.
This is line number 10.

Output (of Skip(2).IgnoreLast(1)):

This is line number 3.
This is line number 4.
This is line number 5.
This is line number 6.
This is line number 7.
This is line number 8.
This is line number 9.
Dan Tao