2013-03-01 116 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