将C#ReadLine()前进到函数调用中的下一行

时间:2009-09-23 16:11:50

标签: c# readline

在我的C#应用​​程序中,我试图将ReadLine()输入一个简单的文本文档,其中7位数字符串逐行分隔。我试图做的是每次调用函数时抓取下一个7位数字符串。这是我到目前为止所做的:

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;
    }

每次调用invoiceNumberFunc()时,如何前进到下一行?

提前致谢。

6 个答案:

答案 0 :(得分:8)

您需要在调用之间保持StreamReader,或者将其作为新参数传递给方法,或者将其作为类的成员变量。

我个人更喜欢把它变成一个参数的想法,所以它永远不会成为一个成员变量 - 这会让生活更容易管理:

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;
}

答案 1 :(得分:2)

您不能,因为您在函数中创建和处理流阅读器。想到两种方式:

您可以将流阅读器存储在成员变量中,或者一次性读取所有内容并将数组存储在成员变量中。

或者通过将返回类型更改为IEnumerable<string>并将using块中的部分更改为:

来使其成为迭代器方法
while ((invoiceNumber = sr.ReadLine()) != null) {
    yield return invoiceNumber;
}

这样,您就可以在foreach上致电invoiceNumberFunc

答案 2 :(得分:1)

您需要使用相同的StreamReader而不是创建新的StreamReader。每次你创建一个新的并处理旧文件时,你都会在文件的开头回来。

尝试在流中传递相同的StreamReader引用或保留您在流中的位置记录,并在必要时在基本流上使用Seek()。我个人推荐第一个。

答案 3 :(得分:1)

你需要重做这个,所以你不是在方法中创建流程读取器,而是在类级别创建它,只是在方法中使用它,然后在完成后处理/关闭读取器。类似的东西:

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;
        }
    }
}

在这种情况下,创建类IDisposable也是一个好主意,这样您就可以验证StreamReader是否已被释放,并且还可能进行“初始化”/“关闭”例程,而不是初始化并关闭我在这里做的事情。

答案 4 :(得分:1)

您正在寻找的是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();
        }
    }
}

现在你可以使用这个函数返回这个函数的简单内容: -

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

或者使用LINQ获得创意。

答案 5 :(得分:1)

另一种方法是使用yield return statement

在迭代器块中转换函数

唯一的办法是确保你在try中添加一个finaly子句并删除catch,因为yield return不能用于裸try / catch。所以你的代码将成为:

    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
        {
        }
    }