2013-03-01 32 views
1

我有一个文本文件,其中包含一个固定长度的表,我试图解析。但是,文件的开头是关于何时生成此表的一般信息(IE时间,数据等)。阅读流与2个不同的阅读器

要阅读本文,我试图制作一个FileStream,然后用StreamReader读取此文件的第一部分。我从文档的顶部解析出我需要的内容,然后在完成后将流的位置设置为结构化数据的第一行。

然后,我将一个TextFieldParser附加到流(具有适当的固定长度表设置),然后尝试读取文件。在第一行中,它失败,并在ErrorLine属性中列出了表的第三行的后半部分。我通过它,它是在第一行阅读,但ErrorLine财产建议,否则。

调试时,我发现如果我在将TextFieldParser附加到流中后尝试使用我的StreamReader.ReadLine()方法,则前两行显示正常。但是,当我读取第三行时,它将返回一行,以第三行的前半部分开头(并在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

你可以发布您的代码?这将有助于识别问题 – VladL 2013-03-01 22:58:12

+0

@VladL好的,我添加了针对该示例的代码。有一点需要注意的是,我将数据添加到“DataTable”并从此函数返回。 – Xantham 2013-03-01 23:09:44

回答

4

跳过的原因是StreamReader正在从FileStream读取数据块,而不是逐字符读取。例如,StreamReader可能会从FileStream读取4千字节,然后根据需要解析出线路以响应ReadLine()调用。因此,当您将TextFieldParser附加到FileStream时,它将从当前文件位置读取 - 这是StreamReader离开它的位置。

的解决方案应该是相当简单:只需连接TextFieldParserStreamReader

TextFieldParser parser = new TextFieldParser(reader); 

TextFieldParser(TextReader reader)

+0

+1:打我吧。 – 2013-03-01 23:36:50

+0

这似乎确实解决了这个问题。告诉我,如果我正确理解这一点。 'Streamreader'在表格的第一行离开(文本方式),该字段(可以说)是方块3的一部分。然后'TextFieldParser.ReadFields()'开始读取块4,它是下一个块。它然后失败,因为它试图只解析我说的宽度的一半。如果我传入'StreamReader',它会强制它从下一个字符开始,而不是在下一个内存块? – Xantham 2013-03-02 00:37:21

+1

@ Xantham:是的,你有这个概念。 'StreamReader'把一些角色放在口袋里。通过将'TextFieldReader'附加到'StreamReader',您正在阅读这些字符。随着解析器继续读取,它会请求'StreamReader'中的字符,而StreamReader又会从'FileStream'中获取数据并将其传递给解析器。 – 2013-03-02 05:12:32

1

一般来说,大多数流消耗 - 也就是说,曾经看过,它不再可用。您可以通过编写源自Stream的中间类来分离多个流,并引发事件,重新发布到其他流等。

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); 
,直到你找到所有你需要它不会加载整个文件内容,只是线
+0

但是,这是如何帮助他解析文件的第二部分? – 2013-03-01 23:31:50

+0

@JimMischel尽我所知,他没有问题,只是使用流两次是一个问题 – VladL 2013-03-01 23:33:30

+0

我的观点是,除非我误解,他试图读取文件的前N行为原始行,然后阅读该文件的下一部分用'TextFieldParser'。他遇到的问题是如何在文件的适当位置启动'TextFieldParser'。 – 2013-03-01 23:37:20