0

我使用的一个外部 Windows 服务维护一个基于文本的日志文件,它会不断地附加到该日志文件中。此日志文件会随着时间的推移无限增长。我想定期修剪此日志文件以维护,例如最近的 5mb 日志条目。如何有效地在 C# .NET 4.0 中实现文件 I/O 代码以将文件修剪为 5mb?

更新:设置服务依赖项的方式,我的服务总是在外部服务之前启动。这意味着如果需要,我可以独占访问日志文件以截断它。一旦外部服务启动,我将不会访问日志文件。我可以在桌面启动时获得对文件的独占访问权限。问题是 - 日志文件的大小可能有几 GB,我正在寻找一种有效的方法来截断它。

4

3 回答 3

1

它将占用您要存储的内存量来处理“新”日志文件,但如果您只想要 5Mb,那么它应该没问题。如果您在谈论 Gb+,那么您可能还有其他问题;但是,它仍然可以使用临时文件和一些锁定来完成。

如前所述,您可能会遇到竞争条件,但如果这是写入此文件的唯一线程,则情况并非如此。这将替换您当前对文件的写入。

const int MAX_FILE_SIZE_IN_BYTES = 5 * 1024 * 1024; //5Mb;
const string LOG_FILE_PATH = @"ThisFolder\log.txt";
string newLogMessage = "Hey this happened";


#region Use one or the other, I mean you could use both below if you really want to.
//Use this one to save an extra character
if (!newLogMessage.StartsWith(Environment.NewLine))
    newLogMessage = Environment.NewLine + newLogMessage;

//Use this one to imitate a write line
if (!newLogMessage.EndsWith(Environment.NewLine))
    newLogMessage = newLogMessage + Environment.NewLine; 
#endregion

int newMessageSize = newLogMessage.Length*sizeof (char);
byte[] logMessage = new byte[MAX_FILE_SIZE_IN_BYTES];
//Append new log to end of "file"
System.Buffer.BlockCopy(newLogMessage.ToCharArray(), 0, logMessage, MAX_FILE_SIZE_IN_BYTES - newMessageSize, logMessage.Length);


FileStream logFile = File.Open(LOG_FILE_PATH, FileMode.Open, FileAccess.ReadWrite);

int sizeOfRetainedLog = (int)Math.Min(MAX_FILE_SIZE_IN_BYTES - newMessageSize, logFile.Length);
//Set start position/offset of the file
logFile.Position = logFile.Length - sizeOfRetainedLog;
//Read remaining portion of file to beginning of buffer
logFile.Read(logMessage, logMessage.Length, sizeOfRetainedLog);

//Clear the file
logFile.SetLength(0); 
logFile.Flush();

//Write the file
logFile.Write(logMessage, 0, logMessage.Length);

我写得很快,如果我在某处落后 1 点,我深表歉意。

于 2013-02-15T22:50:45.253 回答
0

取决于它被写入的频率,我会说您可能面临修改文件而不损坏日志的竞争条件。您总是可以尝试编写一个服务来监视文件大小,一旦达到某个点锁定文件,欺骗并清除整个内容并关闭它。然后将数据存储在服务轻松控制大小的另一个文件中。或者,您可以查看外部服务是否有记录到数据库的选项,这将使推出最旧的数据变得非常简单。

于 2013-02-15T22:19:43.773 回答
0

您可以使用文件观察器来监视文件:

FileSystemWatcher logWatcher = new FileSystemWatcher();
        logWatcher.Path = @"c:\example.log"
        logWatcher.Changed += logWatcher_Changed;

然后,当引发事件时,您可以使用 StreamReader 读取文件

private void logWatcher_Changed(object sender, FileSystemEventArgs e)
    {
     using (StreamReader readFile = new StreamReader(path))
        {
            string line;
            string[] row;
            while ((line = readFile.ReadLine()) != null)
            {
               // Here you delete the lines you want or move it to another file, so that your log keeps small. Then save the file. 
            }
        }
    }

这是一个选择。

于 2013-02-15T22:25:09.783 回答