Ryan Michela
Ryan Michela

Reputation: 8374

How to open a file for non-exclusive write access using .NET

Is it possible to open a file in .NET with non exclusive write access? If so, how? My hope is to have two or more processes write to the same file at the same time.

Edit: Here is the context of this question: I am writing a simple logging HTTPModule for IIS. Since applications running in different app pools run as distinct processes, I need a way to share the log file between processes. I could write a complex file locking routine, or a lazy writer, but this is a throw away project so its not important.

This is the test code I used to figure out the process.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading;

namespace FileOpenTest
{
    class Program
    {
        private static bool keepGoing = true;

        static void Main(string[] args)
        {
            Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);

            Console.Write("Enter name: ");
            string name = Console.ReadLine();
            //Open the file in a shared write mode
            FileStream fs = new FileStream("file.txt", 
                                           FileMode.OpenOrCreate, 
                                           FileAccess.ReadWrite, 
                                           FileShare.ReadWrite);

            while (keepGoing)
            {
                AlmostGuaranteedAppend(name, fs);
                Console.WriteLine(name);
                Thread.Sleep(1000);
            }

            fs.Close();
            fs.Dispose();
        }

        private static void AlmostGuaranteedAppend(string stringToWrite, FileStream fs)
        {
            StreamWriter sw = new StreamWriter(fs);

            //Force the file pointer to re-seek the end of the file.
            //THIS IS THE KEY TO KEEPING MULTIPLE PROCESSES FROM STOMPING
            //EACH OTHER WHEN WRITING TO A SHARED FILE.
            fs.Position = fs.Length;

            //Note: there is a possible race condition between the above
            //and below lines of code. If a context switch happens right
            //here and the next process writes to the end of the common
            //file, then fs.Position will no longer point to the end of
            //the file and the next write will overwrite existing data.
            //For writing periodic logs where the chance of collision is
            //small, this should work.

            sw.WriteLine(stringToWrite);
            sw.Flush();
        }

        private static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
        {
            keepGoing = false;
        }
    }
}

Upvotes: 7

Views: 6240

Answers (4)

Jim Fell
Jim Fell

Reputation: 14256

I found a very helpful answer posted on procbits.com:

Log file generator: (1st process)

static void Main(string[] args) {
    var file = @"C:\logfile.txt";
    var fs = File.Open(file, FileMode.Append, FileAccess.Write, FileShare.Read);
    var sw = new StreamWriter(fs);
    sw.AutoFlush = true;
    sw.WriteLine("some data");
    sw.WriteLine("some data2"); //set breakpoint here

    sw.Close();
}

Log file reader: (2nd process)

static void Main(string[] args) {
    var file = @"C:\logfile.txt";
    var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
    var sr = new StreamReader(fs);

    var l1 = sr.ReadLine();
    var l2 = sr.ReadLine();

    sr.Close();
}

In short this works because the FileShare permissions are set properly.

Upvotes: 0

hmcclungiii
hmcclungiii

Reputation: 1805

Not possible. Learn about how files are read/written to disc.

Edit: Since all the downvotes, I guess I'll explain a little more. It is absolutely impossible for more than one process to write to the same file at the same exact time. When one process is writing, the file will normally be unavailable to other writers, meaning that the other processes would have to wait until the file is no longer being written to by the first process.

Upvotes: -1

Rob McCready
Rob McCready

Reputation: 1919

The FileStream class has a constructor that takes several options including FileShare

new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);

Upvotes: 6

David Morton
David Morton

Reputation: 16505

Use the FileShare enumeration when opening the file using File.Open. Specifically, use FileShare.ReadWrite.

Upvotes: 7

Related Questions