在我的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()时,如何前进到下一行?
提前致谢。
答案 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
{
}
}