How can I delete the oldest lines in a file when using FileStream and StreamWriter?
Based on Prakash's answer here , I thought I'd try something like this to remove the oldest lines in the file before adding a new line to it:
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 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();
}
... but in my version of .NET (Compact Framework, Windows CE C # project in VS 2008) neither ReadAllLines () nor WriteAllLines () are available.
What is the ReadAllLines / WriteAllLines method capable of accomplishing the same thing?
UPDATE
This is undoubtedly kludgy, but it looks like it should work and I'm going to check it out. I moved the "shrink log file" code from the WriteLog () method to the constructor:
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 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();
}
source to share
ReadAllLines
and WriteAllLines
just hide the noose from you. Just do:
StreamReader reader = new StreamReader(_fileStream);
List<String> logList = new List<String>();
while (!reader.EndOfStream)
logList.Add(reader.ReadLine());
Note that this is almost identical to the implementation File.ReadAllLines
(from MSDN Reference Source )
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
is simialr:
StreamWriter writer = new StreamWriter(path, false); //Don't append!
foreach (String line in logList)
{
writer.WriteLine(line);
}
source to share
I would write simple extension methods for this that do the job lazily without loading the entire file into memory.
Usage would be something like this:
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);
}
}
}
source to share