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.
source to share
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;
}
source to share
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
.
source to share
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.
source to share
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.
source to share
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.
source to share
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
{
}
}
source to share