2009-05-06 10 views
1

見出しと本文があるテキストファイルを解析しようとしています。このファイルの見出しには、本文のセクションへの行番号の参照があります。たとえば:一部のコンテンツをスキップしてC#でテキストファイルを解析する

SECTION_A 256 
SECTION_B 344 
SECTION_C 556 

これはSECTION_A辞書、その後、必要なときにセクションをお読みにこの見出しを解析するための最良の方法だろう何行に256

を開始することを意味します。

典型的なシナリオは次のようになります

  1. ヘッダを解析し、ヘッダを解析し、各セクションの拳段落を読み取り専用セクションSECTION_B
  2. を読み取ります。

データファイルはかなり大きく、メモリにすべてをロードしてから操作することは間違いありません。

私はあなたの提案を感謝します。私の環境はVS 2008とC#3.5 SP1です。

答えて

2

明らかに、名前+行番号を辞書に保存することはできますが、それはあなたにはうまく行かないでしょう。

確かに、どの行から読み始めているのかを知ることができますが、問題はファイル内のどこの行ですか?知る唯一の方法は、最初から始めてカウントを開始することです。

テキストコンテンツをデコードして(エンコードの問題がある場合)、行番号からバイト位置へのマッピングタイプを指定できるラッパーを作成するのが最善の方法です。その行番号、256、およびディクショナリを調べて、ファイル内の位置10000から256行目が始まり、そこから読み込みを開始することを確認します。

これは一度限りの処理ですか?もしそうでなければ、ファイル全体をSQLiteデータベースのようなローカルデータベースに詰め込むことを考えましたか?これにより、行番号とその内容の間に直接的なマッピングができます。もちろん、そのファイルは元のファイルよりも大きく、テキストファイルからデータベースにデータをコピーする必要があるため、どちらかのオーバーヘッドがあります。

+0

私はそれを操作し始める前にファイルを前処理しなければならないことに感謝しました。データファイルがあまりにも頻繁に変更されるので、外部データベースは私のためのオプションではありません。あなたの答えはありがたいです –

+0

あなたはそれについて怠け者になり、最初から興味のある部分だけに前処理を行います。その時点までの0秒まで.Seek():可能です。後半の部分に興味がある場合は、どこから出発しても前処理を続けることができます。また、後で使用するためにタイムスタンプと識別可能な情報とともにインデックスを格納する(またはデータが更新されたときに完全に削除する)。 –

+0

私はPasiの提案が好きです、ありがとう! –

0

一度に1行ずつファイルを読み込み、必要なものに達するまでデータを無視してください。メモリの問題はありませんが、パフォーマンスはあまり良くありません。しかし、これはバックグラウンドスレッドで簡単に行うことができます。

+0

ヘッダーに定義されている必要なセクションを行番号でソートし、その順序で読み取って1つのパススルーしか必要ないようにすることをお勧めします。 –

0

ヘッダーの最後までファイルを読み込みます。その後、

Dictionary<string, int> sectionIndex = new Dictionary<string, int>(); 
List<string> headers = new List<string>(); // fill these with readline 

foreach(string header in headers) { 
    var s = header.Split(new[]{' '}); 
    sectionIndex.Add(s[0], Int32.Parse(s[1])); 
} 

が希望辞書のエントリを検索しますが、その行番号を打つまで、ファイルを読み込む行数のカウント、およびループを保つ:そうのように、あなたは空白に保存されてきた文字列を分割します次のセクションの開始行に達するまで読んでください。辞書のキーの順序を保証できるかどうかわからないので、おそらく現在と次のセクションの名前が必要になるでしょう。

読んでいるセクションが読んでいるセクションの前にないことを確認するために、エラーチェックをしてください。

0

すべての見出し情報がキャプチャされ、停止するまで行単位で読むことができます(すべてのセクションポインタが見出しにあると仮定します)。後でデータを取り出す際に使用するセクション番号と行番号があります。

string dataRow = ""; 

try 
{ 
    TextReader tr = new StreamReader("filename.txt"); 

    while (true) 
    { 
     dataRow = tr.ReadLine(); 
     if (dataRow.Substring(1, 8) != "SECTION_") 
      break; 
     else 
      //Parse line for section code and line number and log values 
      continue; 
    } 
    tr.Close(); 
} 
catch (Exception ex) 
{ 
    MessageBox.Show(ex.Message); 
} 
3

これは非常に簡単です。

問題には3つの部分があります。

1)ファイル内の行の検索方法。これを行う唯一の方法は、ファイルから行を読み込み、その行のファイルに開始位置を記録するリストを保持することです。例:

 
List lineMap = new List(); 
lineMap.Add(0); // Line 0 starts at location 0 in the data file (just a dummy entry) 
lineMap.Add(0); // Line 1 starts at location 0 in the data file 

using (StreamReader sr = new StreamReader("DataFile.txt")) 
{ 
    String line; 
    int lineNumber = 1; 
    while ((line = sr.ReadLine()) != null) 
     lineMap.Add(sr.BaseStream.Position); 
} 

2)インデックスファイルを読み込んで解析します。その後

 
Dictionary index = new Dictionary(); 

using (StreamReader sr = new StreamReader("IndexFile.txt")) 
{ 
    String line; 
    while ((line = sr.ReadLine()) != null) 
    { 
     string[] parts = line.Split(' '); // Break the line into the name & line number 
     index.Add(parts[0], Convert.ToInt32(parts[1])); 
    } 
} 

は、あなたのファイルの行を見つけるために使用:

 
int lineNumber = index["SECTION_B";];   // Convert section name into the line number 
long offsetInDataFile = lineMap[lineNumber]; // Convert line number into file offset 

は次に(offsetInDataFile、SeekOrigin.Begin)シーク、DataFile.txtに新しいのFileStreamを開くの先頭に移動します(上記のように)StreamReaderを使用して行を読み込みます。

+0

+1私のより良い答え – ajdams

関連する問題