我有一个随时间附加的文本文件,并且周期性地将其截断为一定的大小,例如, 10MB,但保留最后的10MB而不是第一个。如何将文件截断为特定大小但保留最终部分?
有没有什么聪明的方法可以做到这一点?我猜我应该寻求正确的观点,从那里读入一个新文件,删除旧文件并将新文件重命名为旧名称。任何更好的想法或示例代码?理想情况下,我不会将整个文件读入内存,因为该文件可能很大。
请使用log4net的等
我有一个随时间附加的文本文件,并且周期性地将其截断为一定的大小,例如, 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 has a blog post on exactly that topic, too.
您可以将文件读取到二进制流中,并使用seek方法来检索最后10MB的数据并将它们加载到内存中。然后将此流保存到一个新文件中,并删除旧文件。文本数据可能会被截断,因此您必须确定这是否可以解决。
在这里寻找Seek方法的一个例子:
是由MiniTech移动提供的代码示例可能是我porposition :) –
我测试从“假”的解决方案,但它不适用于我,它修剪文件,但保持它的开始,而不是结束。
我怀疑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);
}
}
我在我的环境中确认了这一点(Win8.1 Pro,WMC 64位,.NET 4.6.1,C#)。在我的特殊情况下,'ms.CopyTo(s)'不起作用。使用'fs.Write(ms.GetBuffer(),0,trimSize);'(我正在使用[this](http://stackoverflow.com/a/11072529/1273042)解决方案)更改它。 +1指出问题(: – mishamosher
+1可能还需要一实现方式ms.Position = 0最终CopyTo从()(我使用之前另一个FileStream不是MemoryStream) – StuartLC
@nonnb:好点;谢谢。 – Ryan
@minitech看来你的代码只能从.NET 4.0开始工作。我发现,虽然编码在我的.NET 3.5项目。 – Alex