2012-06-17 94 views
9

我有一个随时间附加的文本文件,并且周期性地将其截断为一定的大小,例如, 10MB,但保留最后的10MB而不是第一个。如何将文件截断为特定大小但保留最终部分?

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

请使用log4net的等

回答

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); 
    } 
} 
+4

+1可能还需要一实现方式ms.Position = 0最终CopyTo从()(我使用之前另一个FileStream不是MemoryStream) – StuartLC

+0

@nonnb:好点;谢谢。 – Ryan

+0

@minitech看来你的代码只能从.NET 4.0开始工作。我发现,虽然编码在我的.NET 3.5项目。 – Alex

4

你不需要写之前读取整个文件,特别是没有如果你正在写到不同的文件中没有任何建议。你可以分块工作;读一点,写作,再读一点,再写一遍。事实上,这就是所有I/O都是如何完成的。特别是对于较大的文件,您永远不会真正想要一次读取它们。

但是,您提出的是从文件开头删除数据的唯一方法。你必须重写它。 Raymond Chen has a blog post on exactly that topic, too.

1

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

在这里寻找Seek方法的一个例子:

http://www.dotnetperls.com/seek

+0

是由MiniTech移动提供的代码示例可能是我porposition :) –

2

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

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

我在我的环境中确认了这一点(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

相关问题