Locking Subsections of a File






Locking Subsections of a File

Problem

You need to read or write data from or to a section of a file, and you want to make sure that no other processes or threads can access, modify, or delete the file until you have finished with it.

Solution

Locking out other processes from accessing your file while you are using it is accomplished through the Lock method of the FileStream class. The following code creates a file from the fileName parameter and writes two lines to it. The entire file is then locked using the Lock method. While the file is locked, the code goes off and does some other processing; when this code returns, the file is closed, thereby unlocking it:

	public static void CreateLockedFile(string fileName)
	{
	    using (FileStream fileStream = new FileStream(fileName,
	              FileMode.Create,
	              FileAccess.ReadWrite,
	              FileShare.ReadWrite))

	    {
	        using (StreamWriter streamWriter = new StreamWriter(fileStream))
	        {
	             streamWriter.WriteLine("The First Line");
	             streamWriter.WriteLine("The Second Line");
	             streamWriter.Flush( );

	             // Lock all of the file.
	             fileStream.Lock(0, fileStream.Length);

	             // Do some lengthy processing here…
	             Thread.Sleep(1000);

	             // Make sure we unlock the file.
	             // If a process terminates with part of a file locked or closes a file
	             // that has outstanding locks, the behavior is undefined which is MS
	             // speak for bad things….
	             fileStream.Unlock(0, fileStream.Length);

	             streamWriter.WriteLine("The Third Line");
	        }
	    }
	}

Discussion

If a file is opened within your application and the FileShare parameter of the FileStream.Open call is set to FileShare.ReadWrite or FileShare.Write, other code in your application can view or alter the contents of the file while you are using it. To handle file access with more granularity, use the Lock method of the FileStream object to prevent other code from overwriting all or a portion of your file. Once you are done with the locked portion of your file, you can call the Unlock method on the FileStream object to allow other code in your application to write data to that portion of the file.

To lock an entire file, use the following syntax:

	fileStream.Lock(0, fileStream.Length);

To lock a portion of a file, use the following syntax:

	fileStream.Lock(4, fileStream.Length - 4);

This line of code locks the entire file except for the first four characters. Note that you can lock an entire file and still open it multiple times, as well as write to it.

If another thread is accessing this file, it is possible to see an IOException thrown during the call to either the Write, Flush, or Close methods. For example, the following code is prone to such an exception:

	public static void CreateLockedFile(string fileName)
	{

	    using (FileStream fileStream = new FileStream(fileName,
	                                   FileMode.Create,
	                                   FileAccess.ReadWrite,
	                                   FileShare.ReadWrite))

	    {
	        using (StreamWriter streamWriter = new StreamWriter(fileStream))
	        {
	            streamWriter.WriteLine("The First Line");
	            streamWriter.WriteLine("The Second Line");
	            streamWriter.Flush( );

	            // Lock all of the file.
	            fileStream.Lock(0, fileStream.Length);

	            using (StreamWriter streamWriter2 = new StreamWriter(
	                          new FileStream(fileName,
	                                         FileMode.Open,
	                                         FileAccess.Write,
	                                         FileShare.ReadWrite)))
	            {
	                streamWriter2.Write("foo ");
	                try
	                {
	                    streamWriter2.Close( ); // --> Exception occurs here!
	                }
	                catch
	                {
	                  Console.WriteLine(
	               "The streamWriter2.Close call generated an exception.");
	                }
	                streamWriter.WriteLine("The Third Line");
	            }
	        }
	    }
	}

This code produces the following output:

	The streamWriter2.Close call generated an exception.

Even though streamWriter2, the second StreamWriter object, writes to a locked file, it is when the streamWriter2.Close method is executed that the IOException is thrown.

If the code for this recipe were rewritten as follows:

	public static void CreateLockedFile(string fileName)
	{
	    using (FileStream fileStream = new FileStream(fileName,
	                                   FileMode.Create,

	                                   FileAccess.ReadWrite,
	                                   FileShare.ReadWrite))

	    {
	        using (StreamWriter streamWriter = new StreamWriter(fileStream))
	        {
	            streamWriter.WriteLine("The First Line");
	            streamWriter.WriteLine("The Second Line");
	            streamWriter.Flush( );

	            // Lock all of the file.
	            fileStream.Lock(0, fileStream.Length);

	            // Try to access the locked file…
	            using (StreamWriter streamWriter2 = new StreamWriter(
	                      new FileStream(fileName,
	                                     FileMode.Open,
	                                     FileAccess.Write,
	                                     FileShare.ReadWrite)))
	            {
	                streamWriter2.Write("foo");
	                fileStream.Unlock(0, fileStream.Length);
	                streamWriter2.Flush( );
	            }
	        }
	    }
	}

no exception is thrown. This is due to the fact that the code closed the FileStream object that initially locked the entire file. This action also freed all of the locks on the file that this FileStream object was holding onto. Since the streamWriter2. Write("Foo") method had written Foo to the stream's buffer (but had not flushed it), the string Foo was still waiting to be flushed and written to the actual file. Keep this situation in mind when interleaving the opening, locking, and closing of streams. Mistakes in code sometimes manifest themselves a while after they are written. This leads to some bugs that are more difficult to track down, so tread carefully when using file locking.

See Also

See the "StreamWriter Class" and "FileStream Class" topics in the MSDN documentation.



 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows