2012-06-17 22 views
9

Tôi có tệp văn bản được thêm vào theo thời gian và định kỳ tôi muốn cắt bớt nó xuống một kích thước nhất định, ví dụ: 10MB, nhưng giữ 10MB cuối thay vì đầu tiên.Làm cách nào để cắt bớt một tệp xuống một kích thước nhất định nhưng giữ phần cuối?

Có cách nào thông minh để thực hiện việc này không? Tôi đoán tôi nên tìm đúng điểm, đọc từ đó vào một tệp mới, xóa tệp cũ và đổi tên tệp mới thành tên cũ. Bất kỳ ý tưởng hay mã ví dụ nào tốt hơn? Lý tưởng nhất là tôi sẽ không đọc toàn bộ tệp vào bộ nhớ vì tệp có thể lớn.

Hãy không gợi ý về việc sử dụng Log4Net, vv

Trả lời

4

Nếu bạn đang okay với chỉ đọc 10MB cuối cùng vào bộ nhớ, điều này sẽ làm việc:

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 cũng có thể cần một ms.Position = 0 trước khi CopyTo thức() (Tôi sử dụng một FileStream khác không phải MemoryStream) – StuartLC

+0

@nonnb: Điểm tốt; cảm ơn. – Ryan

+0

@minitech có vẻ như mã của bạn chỉ hoạt động từ .NET 4.0 trở lên. Tôi phát hiện ra rằng trong khi mã hóa trên dự án .NET 3.5 của tôi. – Alex

4

Bạn không cần phải đọc toàn bộ tập tin trước khi viết nó, đặc biệt là không nếu bạn đang viết vào một tập tin khác nhau. Bạn có thể làm việc theo khối; đọc một chút, viết, đọc thêm một chút, viết lại. Trong thực tế, đó là cách tất cả các I/O được thực hiện anyway. Đặc biệt với các tệp lớn hơn, bạn không bao giờ thực sự muốn đọc chúng cùng một lúc.

Nhưng những gì bạn đề xuất là cách duy nhất để xóa dữ liệu khỏi đầu tệp. Bạn phải viết lại nó. Raymond Chen has a blog post on exactly that topic, too.

1

Bạn có thể đọc tệp vào luồng nhị phân và sử dụng phương pháp tìm kiếm để chỉ truy xuất 10MB dữ liệu cuối cùng và tải chúng vào bộ nhớ. Sau đó, bạn lưu luồng này vào một tệp mới và xóa tệp cũ. Các dữ liệu văn bản có thể được cắt ngắn mặc dù vì vậy bạn phải quyết định nếu điều này là ngoại lệ.

Nhìn vào đây để một ví dụ về phương pháp tìm kiếm:

http://www.dotnetperls.com/seek

+0

Có mã ví dụ được cung cấp bởi minitech có thể là một thực hiện porposition của tôi :) –

2

tôi thử nghiệm các giải pháp từ "sai" nhưng nó không làm việc cho tôi, nó trims các tập tin nhưng giữ sự khởi đầu của nó, không phải là kết thúc.

Tôi nghi ngờ rằng CopyTo sao chép toàn bộ luồng thay vì bắt đầu vị trí luồng. Đây là cách tôi đã làm cho nó làm việc:

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

Tôi xác nhận điều này trong môi trường của mình (Win8.1 Pro với WMC 64 bit, .NET 4.6.1, C#). Trong trường hợp cụ thể của tôi, 'ms.CopyTo (s)' không hoạt động đúng. Thay đổi nó bằng 'fs.Write (ms.GetBuffer(), 0, trimSize);' (Tôi đang sử dụng giải pháp [this] (http://stackoverflow.com/a/11072529/1273042)). +1 để chỉ ra vấn đề (: – mishamosher

Các vấn đề liên quan