Как я могу удалить самые старые строки в файле при использовании FileStream и StreamWriter?

Основываясь на ответе Пракаша, я подумал, что попробую что-то вроде этого, чтобы удалить самые старые строки в файле перед добавлением в него новой строки:

private ExceptionLoggingService()
{
    _fileStream = File.OpenWrite(GetExecutionFolder() + "\\Application.log");
    _streamWriter = new StreamWriter(_fileStream);
}

public void WriteLog(string message)
{
    const int MAX_LINES_DESIRED = 1000;

    StringBuilder formattedMessage = new StringBuilder();
    formattedMessage.AppendLine("Date: " + DateTime.Now.ToString());
    formattedMessage.AppendLine("Message: " + message);

    // First, remove the earliest lines from the file if it's grown too much
    List<string> logList = File.ReadAllLines(_fileStream).ToList();
    while (logList.Count > MAX_LINES_DESIRED)
    {
        logList.RemoveAt(0);
    }
    File.WriteAllLines(_fileStream, logList.ToArray());

    _streamWriter.WriteLine(formattedMessage.ToString());
    _streamWriter.Flush();
}

... но в моей версии.NET (Compact Framework, проект Windows CE C# в VS 2008) ни ReadAllLines(), ни WriteAllLines() не доступны.

Что такое вызов ReadAllLines/WriteAllLines?

ОБНОВИТЬ

Это, несомненно, запутано, но кажется, что он должен работать, и я собираюсь проверить его. Я переместил код "сократить файл журнала" из метода WriteLog() в конструктор:

private ExceptionLoggingService()
{
    const int MAX_LINES_DESIRED = 1000;

    string uriPath = GetExecutionFolder() + "\\Application.log";
    string localPath = new Uri(uriPath).LocalPath;
    if (!File.Exists(localPath))
    {
        File.Create(localPath);
    }
    _fileStream = File.OpenWrite(localPath);
    // First, remove the earliest lines from the file if it's grown too much
    StreamReader reader = new StreamReader(_fileStream);
    List<String> logList = new List<String>();
    while (!reader.EndOfStream)
    {
        logList.Add(reader.ReadLine());
    }
    while (logList.Count > MAX_LINES_DESIRED)
    {
        logList.RemoveAt(0);
    }
    if (logList.Count > MAX_LINES_DESIRED)
    {
        _fileStream.Close();
        File.Delete(GetExecutionFolder() + "\\Application.log");
        File.Create(GetExecutionFolder() + "\\Application.log");
        _fileStream = File.OpenWrite(GetExecutionFolder() + "\\Application.log");
    }
    _streamWriter = new StreamWriter(_fileStream);
    foreach (String s in logList)
    {
        _streamWriter.WriteLine(s);
        _streamWriter.Flush();
    }
}

public void WriteLog(string message)
{
    StringBuilder formattedMessage = new StringBuilder();
    formattedMessage.AppendLine("Date: " + DateTime.Now.ToString());
    formattedMessage.AppendLine("Message: " + message);
    _streamWriter.WriteLine(formattedMessage.ToString());
    _streamWriter.Flush();
}

2 ответа

Решение

ReadAllLines а также WriteAllLines просто прячемся от вас. Просто делать:

StreamReader reader = new StreamReader(_fileStream);
List<String> logList = new List<String>();

while (!reader.EndOfStream)
   logList.Add(reader.ReadLine());

Обратите внимание, что это почти идентично реализации File.ReadAllLines (из справочного источника MSDN)

       String line;
        List<String> lines = new List<String>();

        using (StreamReader sr = new StreamReader(path, encoding))
            while ((line = sr.ReadLine()) != null)
                lines.Add(line);

        return lines.ToArray();

WriteAllLines это simialr:

StreamWriter writer = new StreamWriter(path, false); //Don't append!
foreach (String line in logList)
{
   writer.WriteLine(line);
}

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

Использование будет примерно таким:

outfile.MyWriteLines(infile.MyReadLines().Skip(1));

public static class Extensions
{
    public static IEnumerable<string> MyReadLines(this FileStream f)
    {
        var sr = new StreamReader(f);

        var line = sr.ReadLine();
        while (line != null)
        {
            yield return line;
            line = sr.ReadLine();
        }
    }

    public static void MyWriteLines(this FileStream f, IEnumerable<string> lines)
    {
        var sw = new StreamWriter(f);
        foreach(var line in lines)
        {
            sw.WriteLine(line);
        }
    }
}
Другие вопросы по тегам