Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add a single line to the top of text file

My app pulls data and appends it to a text file but I need to find out how I can programmatically look at the first line of the text file and see if it matches the following text:

DateTime,VirtualIP,VirtualPort,VirtualName,DestinationIP,DestPort,Status,Desired

If it does then continue doing the normal function (snippet below), if the first line is not the same as above then I want to insert the above in the first line without overwriting whats currently there. How can I do this? (essentially pushing everything one line down so I can add what I want on the first line)...btw this is being saved as a csv file that can be opened in excel.

try
{
    // ...
    for (int j = 0; j < memberStatus.Result.Count; j++)
    {
        VirtualMemberStatus status = memberStatus.Result[j];

        //text += String.Format("Name: {4}, Member: {0}:{1}, Status: {2}, Desired: {3}" + Environment.NewLine, status.Member.Address, status.Member.Port, status.EffectiveStatus, status.DesiredStatus, virtualKey.Key);
        text += String.Format("{5},{4},{0},{1},{2},{3}" + Environment.NewLine, status.Member.Address, status.Member.Port, status.EffectiveStatus, status.DesiredStatus, virtualKey.Key.Replace(":", ","), DateTime.UtcNow);
    }
}
catch
{
    //ERROR CODE 2
    //MessageBox.Show("Error occurred, check device name (case senstive) and admin group. This error may also occur due to connection loss, try again.");
    errors += String.Format("{0} Error Code: 2, Error occurred, check device name (case senstive) and admin group. This error may also occur due to connection loss, try again." + Environment.NewLine, DateTime.UtcNow);

}

this.resultsTextBox.Text = text;

This file does not get deleted a lot but in the event that it does I want it to have the correct column names at the top. ie:

DateTime,VirtualIP,VirtualPort,VirtualName,DestinationIP,DestPort,Status,Desired
like image 208
nGX Avatar asked Nov 23 '11 00:11

nGX


1 Answers

You need to rewrite the whole file.

  1. open a new (temporary!) file
  2. write header line
  3. for each input line, write line (consider block buffering if performance is a concern)
  4. flush and close output file
  5. ONLY if there were no errors, move the temporary file in-place (by renaming).

This procedure can prevent problems when there is an (IO) error halfway the process

Here is code to do such a thing:

using (var input = new StreamReader("input.txt"))
    using (var output = new StreamWriter("input.txt.temp"))
{
    output.WriteLine("headerline"); // replace with your header :)

    var buf = new char[4096];
    int read = 0;
    do 
    {
        read = input.ReadBlock(buf, 0, buf.Length);
        output.Write(buf, 0, read);
    } while (read > 0);

    output.Flush();
    output.Close();
    input.Close();
}

File.Replace("input.txt.temp", "input.txt", "input.txt.backup");

Note that the sample code even creates a backup. One possible point of improvement would be to explicitely instantiate FileStream(...., FileMode.CreateNew) so as to prevent overwriting the temporary file if a file already exists by that name.

Another solution to that would be, to use System.IO.Path.GetTempFileName(). However, then File.Replace might no longer be efficient and atomic, because the tempfolder might be on another volume/filesystem.

like image 116
sehe Avatar answered Sep 21 '22 14:09

sehe