阅读流与2个不同的读者

时间:2013-03-01 22:49:08

标签: c# stream filestream streamreader fixed-width

我有一个文本文件,其中包含我要解析的固定长度表。但是,文件的开头是关于何时生成此表的一般信息(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;

3 个答案:

答案 0 :(得分:4)

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

解决方案应该非常简单:只需将TextFieldParser连接到StreamReader

TextFieldParser parser = new TextFieldParser(reader);

请参阅TextFieldParser(TextReader 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);