9

時間の経過とともに追加されるテキスト ファイルがあり、定期的に特定のサイズ (10MB など) に切り詰めたいと考えていますが、最初の 10MB ではなく最後の 10MB を保持します。

これを行う賢い方法はありますか?正しいポイントを探し、そこから新しいファイルを読み取り、古いファイルを削除し、新しいファイルの名前を古い名前に変更する必要があると思います。より良いアイデアやサンプルコードはありますか? ファイルが大きくなる可能性があるため、ファイル全体をメモリに読み込まないことが理想的です。

Log4Net などの使用に関する提案はありません。

4

4 に答える 4

4

特に別のファイルに書き込む場合は、書き込む前にファイル全体を読み取る必要はありません。チャンクで作業できます。少し読んで、書いて、もう少し読んで、また書く。実際、とにかくすべての I/O はこの方法で行われます。特に大きなファイルでは、一度にすべてを読みたいとは思わないでしょう。

しかし、あなたが提案するのは、ファイルの先頭からデータを削除する唯一の方法です。書き直さなければなりません。Raymond Chen もまさにそのトピックに関するブログ投稿を行っています。

于 2012-06-17T15:28:17.540 に答える
4

最後の 10MB をメモリに読み込むだけでよければ、これでうまくいくはずです。

using(MemoryStream ms = new MemoryStream(10 * 1024 * 1024)) {
    using(FileStream s = new FileStream("yourFile.txt", FileMode.Open, FileAccess.ReadWrite)) {
        s.Seek(-10 * 1024 * 1024, SeekOrigin.End);
        s.CopyTo(ms);
        s.SetLength(10 * 1024 * 1024);
        s.Position = 0;
        ms.Position = 0; // Begin from the start of the memory stream
        ms.CopyTo(s);
    }
}
于 2012-06-17T15:33:12.637 に答える
2

「false」からソリューションをテストしましたが、うまくいきません。ファイルをトリミングしますが、最後ではなく最初を保持します。

CopyToストリームの位置から開始するのではなく、ストリーム全体をコピーすると思われます。これが私がそれを機能させた方法です:

int trimSize = 10 * 1024 * 1024;
using (MemoryStream ms = new MemoryStream(trimSize))
{
    using (FileStream s = new FileStream(logFilename, FileMode.Open, FileAccess.ReadWrite))
    {
        s.Seek(-trimSize, SeekOrigin.End);

        byte[] bytes = new byte[trimSize];
        s.Read(bytes, 0, trimSize);
        ms.Write(bytes, 0, trimSize);

        ms.Position = 0;
        s.SetLength(trimSize);
        s.Position = 0;
        ms.CopyTo(s);
    }
}
于 2014-06-13T11:45:23.713 に答える
1

ファイルをバイナリ ストリームに読み込み、seek メソッドを使用して最後の 10 MB のデータを取得し、メモリにロードすることができます。次に、このストリームを新しいファイルに保存し、古いファイルを削除します。ただし、テキスト データは切り捨てられる可能性があるため、これが例外かどうかを判断する必要があります。

Seek メソッドの例については、こちらをご覧ください。

http://www.dotnetperls.com/seek

于 2012-06-17T15:30:31.083 に答える