2012-03-09 16 views
3

ファイルの最後のx行を除くすべての行をC#のストリームリーダーに読み込む必要があります。これを行う最善の方法は何ですか?ストリームリーダーから最後のx行を削除します

多くのありがとうございます!

+2

ファイルの最後からx改行を読み取り、ファイルの先頭からその位置まで読み取ります。 –

+0

ファイルから読み込む予定のレコードには、一貫性がありますか(一般的なレコードの長さ、 '\ n'で終わる以外のもの)? –

答えて

3

を、ファイルの終わりまでシークし、 '\ n'文字の逆のバイトを調べることは可能ですか?私は\ nと\ r \ nが存在することを知っています。私は次のコードを作成し、かなり簡単なファイルでテストしました。あなたはあなたが持っているファイルでこれを試すことができますか?私のソリューションは長く見えますが、最初から読んでファイル全体を書き直すよりも速いことがわかります。

public static void Truncate(string file, int lines) 
{ 
    using (FileStream fs = File.Open(file, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) 
    { 
     fs.Position = fs.Length; 

     // \n \r\n (both uses \n for lines) 
     const int BUFFER_SIZE = 2048; 

     // Start at the end until # lines have been encountered, record the position, then truncate the file 
     long currentPosition = fs.Position; 
     int linesProcessed = 0; 

     byte[] buffer = new byte[BUFFER_SIZE]; 
     while (linesProcessed < linesToTruncate && currentPosition > 0) 
     { 
      int bytesRead = FillBuffer(buffer, fs); 

      // We now have a buffer containing the later contents of the file 
      for (int i = bytesRead - 1; i >= 0; i--) 
      { 
       currentPosition--; 
       if (buffer[i] == '\n') 
       { 
        linesProcessed++; 
        if (linesProcessed == linesToTruncate) 
         break; 
       } 
      } 
     } 

     // Truncate the file 
     fs.SetLength(currentPosition); 
    } 
} 

private static int FillBuffer(byte[] buffer, FileStream fs) 
{ 
    if (fs.Position == 0) 
     return 0; 

    int bytesRead = 0; 
    int currentByteOffset = 0; 

    // Calculate how many bytes of the buffer can be filled (remember that we're going in reverse) 
    long expectedBytesToRead = (fs.Position < buffer.Length) ? fs.Position : buffer.Length; 
    fs.Position -= expectedBytesToRead; 

    while (bytesRead < expectedBytesToRead) 
    { 
     bytesRead += fs.Read(buffer, currentByteOffset, buffer.Length - bytesRead); 
     currentByteOffset += bytesRead; 
    } 

    // We have to reset the position again because we moved the reader forward; 
    fs.Position -= bytesRead; 
    return bytesRead; 
} 

あなただけのファイルの末尾を削除することを計画しているので、すべてを書き換えるために無駄なようだ、それは大容量のファイルや。もちろん、小さなN.だ場合は特に、1があれば、誰かが望んだという議論をすることができますすべての行を削除し、最初から最後まで進む方が効率的です。

+0

これのおかげで、明日の最初のことを試みるつもりですが、それは私が必要なものだけを行うように見えます –

+0

美しく働いた。誰もが助けてくれてありがとう。 –

3

あなたは本当にINTOストリームリーダーを読んでいません。実際、あなたが求めているパターンに対しては、StreamReaderはまったく必要ありません。 System.IO.Fileは、あなたの代わりに活用できる便利な静的メソッド「ReadLines」を持っている:

IEnumerable<string> allBut = File.ReadLines(path).Reverse().Skip(5).Reverse(); 

以前の欠陥のあるバージョンを、バックコメントスレッド

List<string> allLines = File.ReadLines(path).ToList(); 
IEnumerable<string> allBut = allLines.Take(allLines.Count - 5); 
+0

あなたは、実行可能な代替手段としてファイル全体を読むことを提案しています(ReadLines.Countはファイル全体を読み込みます)? –

+1

あなたはそうです。私はちょうどいくつかのタイムド・テストを通してそれを実行しました。 2番目の方法は、一貫して高速です。ありがとう。私の答えを更新して最初のオプションを削除します。 – xcud

+0

+1 - 'Chr(13)' - 1バイトを探している間に、バイト単位で自分自身をバイト単位で処理する方がパフォーマンスが向上する可能性がありますが、それでも選択肢よりも速いはずです。 –

3

に応じて、あなたはを参照しているので、私はそれがテキストファイルであると仮定しています。

string[] lines = File.ReadAllLines(@"C:\test.txt"); 

それとも、本当にStreamReadersで作業する必要がある場合:あなたはちょうどあなたがそのような文字列の配列にそれらを読むことができます行を取得したい場合は、それは大きなファイルの場合

using (StreamReader reader = new StreamReader(@"C:\test.txt")) 
     { 
      while (!reader.EndOfStream) 
      { 
       Console.WriteLine(reader.ReadLine()); 
      } 
     } 
+0

'StreamReader'の使用は、OPがテキストについて話していると仮定するのに十分であったはずです。 –

+0

質問を聞いた人がStreamReaderが必要だと分かっていたのか、ファイルを読む必要があると知っていて、オンラインでクイック検索を行い、StreamReaderが表示されたのか分かりませんでした。しかし、はいあなたは正しいです – BryanJ

関連する問題