4

I'm trying to read and write to the same file in a way such that no other program can access the file in between:

  FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);               
  StreamReader sr = new StreamReader(fs);
  StreamWriter sw = new StreamWriter(fs);
  newString = sr.ReadToEnd() + "somethingNew";
  sw.Write(newString);
  fs.Close();

The file is never written to. If I debug I can see that the reader manages to fetch the contents of the file, but the writer does not seem to be able to write to the file. Nothing happens.

I've been looking at this question which seems to be the same as mine. However I'm not able to get it to work.

Community
  • 1
  • 1
EJS
  • 1,011
  • 5
  • 14
  • 28
  • What error are you getting? – Matt Nov 10 '15 at 15:20
  • 4
    try `sw.Flush();` after `Write`. – Habib Nov 10 '15 at 15:21
  • Attaching a `StreamReader` and `StreamWriter` to the same stream (which only has a *single* `Position` value) is likely to cause all sorts of mischief. I'd open two streams onto the same file, a read and a write. – spender Nov 10 '15 at 15:23
  • I know you might like this method, but why not open a file in append mode so it'll always append to the file, or create a new one if needed? – Joshua Bakker Nov 10 '15 at 15:24
  • 1
    @JoshuaBakker it's better to write a method that `Creates the file along with a bool to overwrite / or not ` then within that method if the file exist write to / and or append same thing.. I posted a simple working example – MethodMan Nov 10 '15 at 15:26

4 Answers4

5

Just Flush your changes to file, Have sw.Flush(); before closing the stream. like:

string filePath = "test.txt";
FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
StreamReader sr = new StreamReader(fs);
StreamWriter sw = new StreamWriter(fs);
newString = sr.ReadToEnd() + "somethingNew";
sw.Write(newString);
sw.Flush(); //HERE
fs.Close();

You may see this post simultaneous read-write a file in C# (open multiple streams for reading and writing)

Community
  • 1
  • 1
Habib
  • 219,104
  • 29
  • 407
  • 436
  • 1
    Also wrapping the streams in a `using` statement will call `Flush()` for you. You'll also know that they're being closed of and disposed of at a glance. – Carl Reid Nov 10 '15 at 15:26
  • Adding flush worked. I previously had wrapped it in using, however that did not work. – EJS Nov 10 '15 at 15:34
1

As mentioned above - just add the Flush() to force the data held in the stream to be written to the file. In a comment you mentioned that you had previously used a 'using' statement but this hadn't worked.

Briefly here's why:

  1. A using statement automatically calls Flush() so you don't have to.

  2. When you dispose of a StreamReader (or StreamWriter) - like by using a 'using' statement - the inner stream object is also disposed and you lose the handle to the stream.

Guanxi
  • 3,103
  • 21
  • 38
C. Knight
  • 739
  • 2
  • 5
  • 20
0

@EJS a simple static method that you can use to create a new file if it does not exist as well as write to the same file if it does exist

Simple usage

string path = @"C:\SomePath\Name.txt";

if (!System.IO.File.Exists(path))
{
    WriteAndOrAppendText(path, "File Created");
}
else if (System.IO.File.Exists(path))
{
    WriteAndOrAppendText(path, "New Boot.");             
}

private static void WriteAndOrAppendText(string path, string strText)
{
    if (!File.Exists(path))
    {
        using (StreamWriter fileStream = new StreamWriter(path, true))
        {
            fileStream.WriteLine(strText);
            fileStream.Flush();
            fileStream.Close();
        }
    }
    else
    {
        using (StreamWriter fileStream2 = new StreamWriter(path, true))
        {
            fileStream2.WriteLine(strText);
            fileStream2.Flush();
            fileStream2.Close();
        }
    }
}
MethodMan
  • 18,625
  • 6
  • 34
  • 52
  • 2
    What's the difference of the code in `if` & `else` in `WriteAndOrAppendText` method ? – Michael Nov 10 '15 at 15:26
  • Probably better to put your `StreamReader` and `StreamWriter` in a `using` statement rather than an explicit call to `Close`, so that things get cleaned up when stuff goes wrong. – spender Nov 10 '15 at 15:28
  • @spender I totally agree but this was something quick and dirty to help the OP understand the logical flow. doing this way will also avoid getting the `infamous File Already in User Error` – MethodMan Nov 10 '15 at 15:29
0

For being able to create a file, append to it, and read the data in it while still allowing an application to write to it, as I believe you are trying to do, here's a set up I created:

    string path = @"C:\SomePath\MyLogFile.txt";

    public static string Log(string Message)
    {
        try
        {
            if (File.Exists(path) == false)
                File.Create(path).Close();  // need this .Close()!!!

            logCounter++;
            string logString = logCounter + "   " + DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString() + ": " + Message + Environment.NewLine;

            using (FileStream fs = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
            {
                using (StreamWriter sw = new StreamWriter(fs))
                {
                    sw.Write(logString);
                }
            }

            return logString; // only necessary so we can return an error in the Exception block
        }
        catch (Exception ex)
        {
            return "Logger:  Cannot log data. " + ex.ToString();
        }
    }

It's actually required to use FileAccess.Write if you do FileMode.Append - instead of being able to use FileAccess.ReadWrite - but I found that didn't matter because whatever had been written would have been closed and flushed to the file, and I could still open the file and read it (it wouldn't be locked & blank) using these. I have sw.Write() because I have Environment.NewLine that I added into my logString, but I could've done sw.WriteLine() and removed that, if I had wanted to.

One caveat: File.Exists() has issues if the path is long - can't remember the limit, but just know that there is one, so don't put your file you're writing to several layers deep. Less is always better.

vapcguy
  • 7,097
  • 1
  • 56
  • 52