Go to C # ReadLine () for next line in function call

In my C # application, I am trying to feed to ReadLine () a simple text document with 7 digit lines separated by lines. What I am trying to do is grab the next 7 digit string on every function call. Here's what I have so far:

string invoiceNumberFunc()
    {
        string path = @"C:\Users\sam\Documents\GCProg\testReadFile.txt";
        try
        {
            using (StreamReader sr = new StreamReader(path))
            {
                invoiceNumber = sr.ReadLine();

            }

        }
        catch (Exception exp)
        {
            Console.WriteLine("The process failed: {0}", exp.ToString());
        }
       return invoiceNumber;
    }

      

How do I go to the next line every time invoiceNumberFunc () is called?

Thanks in advance.

+2


source to share


6 answers


You will need to hold StreamReader

between calls, either passing it into the method as a new parameter or making it a member variable of the class.

Personally, I prefer the idea that it becomes a parameter so that it never ends up as a member variable, which makes lifecycle management easier:



void DoStuff()
{
    string path = @"C:\Users\sam\Documents\GCProg\testReadFile.txt";
    using (StreamReader sr = new StreamReader(path))
    {
        while (keepGoing) // Whatever logic you have
        {
            string invoice = InvoiceNumberFunc(sr);
            // Use invoice
        }
    }
}

string InvoiceNumberFunc(TextReader reader)
{
    string invoiceNumber;
    try
    {
        invoiceNumber = reader.ReadLine();
    }
    catch (Exception exp)
    {
        Console.WriteLine("The process failed: {0}", exp.ToString());
    }
    return invoiceNumber;
}

      

+8


source


You cannot, as you are creating and deleting a stream reader in a function. Two ways come to mind:

You can store the stream reader in a member variable, or read all at once and store the array in a member variable.

Or you would make it an iterator method by changing the return type to IEnumerable<string>

and changing the part in the block using

to:



while ((invoiceNumber = sr.ReadLine()) != null) {
    yield return invoiceNumber;
}

      

This way you can call foreach

on invoiceNumberFunc

.

+2


source


You need to use the same StreamReader and not create a new one. Every time you create a new one and delete the old one, you start right at the beginning of the file.

Try passing the same StreamReader or keeping a record of the position you are in the stream and using Seek () on the underlying stream if necessary. I would recommend the first one personally.

+1


source


You need to rework this so that you don't create a stream reader inside the method, but rather create it at the class level and just use it in the method, then delete / close the reader when you're done. Something like:

class MyClass
{
    private StreamReader sr;

    string invoiceNumberFunc()
    {
        if (sr == null) 
            sr = new StreamReader(path);

        if (sr.EndOfStream)  {
            sr.Close();
            sr = null;
            return string.Empty;
        }

        try {
            return sr.ReadLine();
        }
        catch(Exception exp) {
            Console.WriteLine("Process failed {0}",exp.ToString());
            return string.Empty;
        }
    }
}

      

In this case it might also be a good idea to make your class IDisposable

so you can make sure the StreamReader gets deleted and also potentially do initialization / closing of routines instead of doing initialization and shutdown like I did.

+1


source


What you are looking for is the command yield

: -

IEnumerable<string> GetInvoiceNumbers()
{
    string path = @"C:\Users\sam\Documents\GCProg\testReadFile.txt";
    using (StreamReader sr = new StreamReader(path))
    {
        while (!sr.EndOfStream)
        {
           yield return sr.ReadLine();
        }
    }
}

      

Now you can use return for this function simple for everyone: -

foreach(string invoiceNumber in GetInvoiceNumbers())
{
   //Do Stuff with invoice number
}

      

Or create a declaration in LINQ.

+1


source


Another way to do this is to convert your function to an iterator block using the return return statement

The only thing to do is to add a finaly clause to your attempt and remove the catch as yield returns cannot be used in a bare try / catch. Thus, your code will become:

    IEnumerable<String> invoiceNumberFunc()
    {
        string path = @"C:\Users\sam\Documents\GCProg\testReadFile.txt";
        try
        {
            using ( System.IO.StreamReader sr = new System.IO.StreamReader( path ) )
            {
                String invoiceNumber;
                while ( ( invoiceNumber = sr.ReadLine() ) != null )
                {
                    yield return sr.ReadLine();
                }
            }
        }
        finally
        {
        }
    }

      

+1


source







All Articles