我有一个文本文件,其中包含我要解析的固定长度表。但是,文件的开头是关于何时生成此表的一般信息(IE时间,数据等)。
要阅读此内容,我尝试制作FileStream
,然后使用StreamReader
阅读此文件的第一部分。我从文档的顶部解析出我需要的东西,然后当我完成后,将流的位置设置为结构化数据的第一行。
然后我将TextFieldParser
附加到流(具有固定长度表的适当设置),然后尝试读取该文件。在第一行,它失败,并在ErrorLine
属性中,它列出了表的第三行的后半部分。我走过它,它在第一行阅读,但ErrorLine
属性建议不这样做。
调试时,我发现如果在将StreamReader.ReadLine()
附加到流后我尝试使用TextFieldParser
方法,则前两行显示正常。但是,当我读取第三行时,它返回一行,它从第三行的前半部分开始(并且在ErrorLine
中的文本所在的位置停止)将在文档的后面添加一些部分。如果我在附加TextFieldParser
之前尝试此操作,它会正确读取所有3行。
我有一种感觉,这与我将2位读者绑在同一个流上有关。我不确定如何用结构化部分和非结构化部分来阅读它,而不仅仅是自己标记行。我可以做到这一点,但我认为我不是第一个想要以单向方式读取部分流,而在另一方面读取流的一部分的人。
为什么它会像这样跳过,你会如何读取不同格式的文本文件?
示例:
Date: 3/1/2013
Time: 3:00 PM
Sensor: Awesome Thing
Seconds X Y Value
0 5.1 2.8 55
30 4.9 2.5 33
60 5.0 5.3 44
为此简化示例量身定制的代码:
Boolean setupInfo = true;
DataTable result = new DataTable();
String[] fields;
Double[] dFields;
FileStream stream = File.Open(filePath,FileMode.Open);
StreamReader reader = new StreamReader(stream);
String tempLine;
for(int j = 1; j <= 7; j++)
{
result.Columns.Add(("Column" + j));
}
//Parse the unstructured part
while(setupInfo)
{
tempLine = reader.ReadLine();
if( tempLine.StartsWith("Date: "))
{
result.Rows.Add(tempLine);
}
else if (tempLine.StartsWith("Time: "))
{
result.Rows.Add(tempLine);
}
else if (tempLine.StartsWith("Seconds")
{
//break out of this loop because the
//next line to be read is the unstructured part
setupInfo = false;
}
}
//Parse the structured part
TextFieldParser parser = new TextFieldParser(stream);
parser.TextFieldType = FieldType.FixedWidth;
parser.HasFieldsEnclosedInQuotes = false;
parser.SetFieldWidths(10, 10, 10, 10);
while (!parser.EndOfData)
{
if (reader.Peek() == '*')
{
break;
}
else
{
fields = parser.ReadFields();
if (parseStrings(fields, out dFields))
{
result.Rows.Add(dFields);
}
}
}
return result;
答案 0 :(得分:4)
它跳过的原因是StreamReader
正在读取FileStream
的数据块,而不是逐个字符地读取。例如,StreamReader
可能会从FileStream
读取4千字节,然后根据需要解析这些行以响应ReadLine()
个调用。因此,当您将TextFieldParser
附加到FileStream
时,它会从当前文件位置读取 - 这是StreamReader
离开它的位置。
解决方案应该非常简单:只需将TextFieldParser
连接到StreamReader
:
TextFieldParser parser = new TextFieldParser(reader);
答案 1 :(得分:1)
一般来说,大多数流都在消耗 - 也就是说,一旦读取,它就不再可用了。您可以通过编写从Stream派生的中间类来分叉到多个流,并且可以引发事件,重新发布到其他流等等。
答案 2 :(得分:0)
在您的情况下,您不需要StreamReader
。最好的选择是检查文件内容是否使用File.ReadLines方法。它不会加载整个文件内容,只会加载直到您找到所需的所有内容:
foreach (string line in File.ReadLines(filePath))
{
if( line.StartsWith("Date: "))
{
result.Rows.Add(line);
}
else if (line.StartsWith("Time: "))
{
result.Rows.Add(line);
}
else if (line.StartsWith("Seconds"))
{
break;
}
}
修改强>
使用LINQ可以做到更简单:
var d = from line in File.ReadLines(filePath) where line.Contains("Date: ") select line;
result.Rows.Add(d);