Усечение начала файла журнала в .NET - PullRequest
3 голосов
/ 24 февраля 2010

У меня есть приложение VB.NET, которое записывает статус в файл журнала в текстовом формате. Со временем размер файла увеличивается, и я хотел узнать, существует ли эффективный способ обрезания начала файла.

Чтобы упростить задачу, я хочу указать размер файла (скажем, 2-3 МБ) и записываю журнал с помощью StreamWriter:

Using strm As New IO.StreamWriter(filelocation.log, True)
    strm.WriteLine("msg to write")
    strm.Close()
End Using

Я думал об использовании strm.BaseStream.Length, чтобы определить, какой объем файла обрезать, но при использовании .SetLength он обрезался бы с конца - не желаемый результат.

Ответы [ 6 ]

2 голосов
/ 24 февраля 2010

Я бы настоятельно рекомендовал посмотреть log4net , чтобы завершить ведение журнала. Это чрезвычайно мощный и гибкий инструмент, в который встроены журналы, основанные на размере, который вы можете указать. Это не тот ответ, который вы ищете здесь, но это определенно стоит посмотреть. Вот пример конфигурации для того, что мы делаем для регистрации во время отладки:

<log4net>
    <appender name="GeneralLog" type="log4net.Appender.RollingFileAppender">
        <file value="ClientTools.log"/>
        <appendToFile value="true"/>
        <maximumFileSize value="3000KB"/>
        <rollingStyle value="Size"/>
        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%d{HH:mm:ss} [%t] %-5p %c - %m%n"/>
        </layout>
    </appender>
    <root>
        <level value="DEBUG"/>
        <appender-ref ref="GeneralLog"/>
    </root>
    <logger name="NHibernate" additivity="false">
        <level value="DEBUG"/>
        <appender-ref ref="GeneralLog"/>
    </logger>
</log4net>

Этот код в файле app.config создаст файл журнала с именем ClientTools.log в папке приложения, запишет его в определенном формате, включая дату и время, и свернет журнал на 3 МБ.

Чтобы использовать регистратор, мы делаем это в Init () веб-страницы: общедоступный журнал ILog;

public void InitiateLogging()
{
    log4net.Config.XmlConfigurator.Configure();
    log = LogManager.GetLogger("MyApplication");
}

А затем, когда вы хотите что-то зарегистрировать, сделайте следующее:

log.Info("No resources available.");
// or
log.Fatal(exception.Message);
// or
log.Warn("Something bad may happen here.");

Вам не нужно беспокоиться о создании объекта потока, закрытии потока, удалении потока и т. Д. И это очень DRY .

0 голосов
/ 19 августа 2016

Быстрый и простой метод, которым я пользуюсь. В этом примере хранятся последние 60 строк файла журнала.

dim LogPath as string = "YourLogPath"    
Dim lineCount = File.ReadAllLines(LogPath).Length

        If lineCount > 60 Then ' because I want my log to be 60 lines long
            Dim delLineCount As Integer = lineCount - 60
            Dim lines As List(Of String) = New List(Of String)(File.ReadAllLines(LogPath))
            lines.RemoveRange(0, delLineCount)
            File.WriteAllLines(LogPath, lines.ToArray())
        End If
0 голосов
/ 11 февраля 2015

Вот пара функций, которые я использую для этого:

private void ShrinkLogFile()
{
    var file = new FileInfo(Filename);
    if (file.Exists && file.Length > MaxFileSize)
    {
        MoveLinesToBeginningStartingAt(file.Length - (MaxFileSize / 2));
    }
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
private void MoveLinesToBeginningStartingAt(long offsetToKeep)
{
    // Open the file twice.  We'll read from the end and write to the beginning.
    using (var fileReader = new FileStream(Filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    using (var fileWriter = new FileStream(Filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
    {
        // Find the end of the first line so we start at the beginning of a new line.
        fileReader.Position = offsetToKeep;
        using (var reader = new StreamReader(fileReader, Encoding.UTF8, true, 512, true))   // Note that we leave fileReader open...
        {
            offsetToKeep += reader.ReadLine().Length;       // Advance offset past the (probably) partial first line
            offsetToKeep += Environment.NewLine.Length;     // Advance past the newline
        }

        // Go to new position and copy the rest of the file to the beginning of the same file.
        fileReader.Position = offsetToKeep;
        fileReader.CopyTo(fileWriter);

        // Truncate the file
        var fileInfo = new FileInfo(Filename);
        fileWriter.SetLength(fileInfo.Length - offsetToKeep);
    }
}

Есть еще несколько вещей, которые следует учитывать:

  1. Вам необходимо запустить их внутри блокировки (xxx), чтобы НЕТ возможности, что другое сообщение попытается записать файл, пока происходит «Сжатие».
  2. Сжатие файла может занять некоторое время, поэтому ваши записи в журнал должны происходить в фоновом потоке.
0 голосов
/ 24 февраля 2010

Вы можете проверить длину файла и усечь его жестким (и грязным) способом:

  If New FileInfo("yourFilePathHere").Length > (2 ^ 21) Then
        File.WriteAllText("yourFilePathHere", _
        File.ReadAllText("yourFilePathHere").Substring(ToInt32(2 ^ 21)))
  End If
0 голосов
/ 24 февраля 2010

Один подход может быть

  1. Читать исходный файл (A) построчно
  2. Пропускать необязательные строки
  3. Запишите необходимые строки в другой файл (B).
  4. сохранить файл B.
  5. Удалить файл A.
  6. Переименование файла B в файл A.
0 голосов
/ 24 февраля 2010

Почему бы не проверить, превышает ли длина файла в байтах 3 МБ, если это так, перезаписать его и записать в него заново. Как-то так, (я парень из C #):

System.IO.FileInfo f = new FileInfo(file_name);
if (f.Length > (1024 * 1024 * 3)){ 
    // File is over 3MB
    //
    // Perhaps back it up?
    // Then...
    using (StreamWriter sw = new StreamWriter(file_name, false))
    {
        // Overwrite the contents....
    }
}else{
    // Open as normal for append mode
}

Надеюсь, это поможет, С наилучшими пожеланиями, Том.

...