如何将文件截断到一定大小但保留结束部分?

我有一个文本文件随着时间的推移附加,并定期我想将其截断到一定的大小,例如10MB,但保留最后10MB而不是第一个。

有没有聪明的方法来做到这一点? 我猜我应该寻找正确的点,从那里读到一个新文件,删除旧文件并将新文件重命名为旧名称。 有更好的想法或示例代码吗? 理想情况下,我不会将整个文件读入内存,因为文件可能很大。

请不要使用Log4Net等建议

如果您只是将最后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); } } 

在编写之前,您不需要读取整个文件,尤其是在写入不同文件时。 你可以分块工作; 读一点,写作,再读一遍,再写一遍。 事实上,无论如何,这就是所有I / O的完成方式。 特别是对于较大的文件,您永远不会想要一次性读取它们。

但你建议的是从文件开头删除数据的唯一方法。 你必须重写它。 Raymond Chen也有关于这个主题的博客文章。

我从“假”测试了解决方案,但它对我不起作用,它修剪文件但保持它的开始,而不是结束。

我怀疑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); } } 

您可以将文件读入二进制流并使用seek方法只检索最后10MB的数据并将其加载到内存中。 然后将此流保存到新文件中并删除旧文件。 文本数据可能会被截断,因此您必须确定这是否可以解决。

在这里查看Seek方法的示例:

http://www.dotnetperls.com/seek