Search code examples
c#c#-4.0filestream

Read, delete, and write to file while locking via FileShare FileShare.None?


This may have been asked before, so I apologize in advance. However, I felt that there are enough pieces here unique to my problem that I wasn't finding that it warranted the question.

I am trying to open a file using the FileStream method. I need to have this file opened under lock from outside read/write, which is why I used the FileShare.None attribute while opening it. Once it is open and locked, I read the contents of the file into a string array line by line. I change one of the lines based on information that needs to be updated, and then I write the lines back to the file.

The problem I am having is that the written lines are appended after the original lines that are read. I need to wipe the file once I have read in from it so that what I write back are the only things in the file.

I am confused because I don't want to close the FileStream and reopen it for write only (which should clear the file), because that would release the lock I have on the file.

FileStream fs = new FileStream("trains.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.None);
StreamReader sr = new StreamReader(fs);
StreamWriter sw = new StreamWriter(fs);

string[] lines = new string[trains.Length];

//Loop through all lines in the file
for (int i = 0; i < lines.Length; i++)
{
    lines[i] = sr.ReadLine();

    /*If the ID of the train in the file matches the parameter, then
        set the line to the InfoLine of the train.*/
    if (lines[i][0].ToString() == train.ID().ToString())
    {
        lines[i] = train.GetInfoLine();
    }
}

//Write back the lines to the file
for (int i = 0; i < lines.Length; i++)
{
    sw.WriteLine(lines[i]);
}

sw.Close();
sr.Close();
fs.Close();

In the above code, trains.Length is simply the length of an array of class objects. GetInfoLine() is a method I have that returns a string of information I want to write to the file.


Solution

  • I would do it as:

    string line = "";
    FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
    StreamReader sr = new StreamReader(fs);
    StreamWriter sw = new StreamWriter(fs);
    
    List<string> lines = new List<string>();
    
    while ((line = sr.ReadLine()) != null)
    {
        line = "*" + line; //Do your processing
        lines.Add(line);
    }
    
    fs.SetLength(0);
    
    foreach (var newline in lines)
    {
        sw.WriteLine(newline);
    }
    sw.Flush();
    fs.Close();
    

    See the fs.SetLength(0);