1

我有一个文本文件,其中包含我要解析的固定长度表。但是,文件的开头是有关何时生成此表的一般信息(IE 时间、数据等)。

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

然后我将 a 附加TextFieldParser到流(使用固定长度表的适当设置),然后尝试读取文件。在第一行,它失败了,在ErrorLine属性中,它列出了表格第三行的后半部分。我穿过它,它在第一行阅读,但该ErrorLine属性表明并非如此。

调试时,我发现如果StreamReader.ReadLine()在将 附加TextFieldParser到流后尝试使用我的方法,前 2 行显示正常。但是,当我阅读第三行时,它会返回一行,该行从第三行的前半部分开始(并在文本所在的位置停止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;
4

3 回答 3

5

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

解决方案应该很简单:只需连接TextFieldParserStreamReader

TextFieldParser parser = new TextFieldParser(reader);

请参阅TextFieldParser(TextReader 阅读器)

于 2013-03-01T23:31:07.340 回答
2

一般来说,大多数流都在消耗——也就是说,一旦读取,它就不再可用了。您可以通过编写一个从 Stream 派生的中间类来分叉到多个流,或者引发事件、重新发布到其他流等。

于 2013-03-01T23:07:16.430 回答
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);
于 2013-03-01T23:28:12.063 回答