2012-06-17 60 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

相關問題