Tuesday, April 5, 2011

File Read/Write Locks

I have an application where I open a log file for writing. At some point in time (while the application is running), I opened the file with Excel 2003, which said the file should be opened as read-only. That's OK with me.

But then my application threw this exception:

System.IO.IOException: The process cannot access the file because another process has locked a portion of the file.

I don't understand how Excel could lock the file (to which my app has write access), and cause my application to fail to write to it!

Why did this happen?

(Note: I didn't observe this behavior with Excel 2007.)

From stackoverflow
  • How do you write the log? Have your own open/close or use some thirty party product?

    I thing that the log is opened and locked only when it writes something. Once the data writing is finished, the code closes the file and, of course, releases the lock

    Hosam Aly : I open a System.IO.FileStream and keep it open until I finish processing some input data. In the case described above, the stream was still open.
  • Here is a logger which will take care of sync locks. (You can modify it to fit to your requirements)

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.IO;
    
    namespace Owf.Logger
    {
        public class Logger
        {
            private static object syncContoller = string.Empty;
            private static Logger _logger;
            public static Logger Default
            {
                get
                {
                    if (_logger == null)
                        _logger = new Logger();
    
                    return _logger;
                }
            }
    
            private Dictionary<Guid, DateTime> _starts = new Dictionary<Guid, DateTime>();
    
            private string _fileName = "Log.txt";
    
            public string FileName
            {
                get { return _fileName; }
                set { _fileName = value; }
            }
    
            public Guid LogStart(string mesaage)
            {
                lock (syncContoller)
                {
                    Guid id = Guid.NewGuid();
    
                    _starts.Add(id, DateTime.Now);
    
                    LogMessage(string.Format("0.00\tStart: {0}", mesaage));
    
                    return id;
                }
            }
    
            public void LogEnd(Guid id, string mesaage)
            {
                lock (syncContoller)
                {
                    if (_starts.ContainsKey(id))
                    {
                        TimeSpan time = (TimeSpan)(DateTime.Now - _starts[id]);
    
                        LogMessage(string.Format("{1}\tEnd: {0}", mesaage, time.TotalMilliseconds.ToString()));
                    }
                    else
                        throw new ApplicationException("Logger.LogEnd: Key doesn't exisits.");
                }
            }
    
            public void LogMessage(string message)
            {
                lock (syncContoller)
                {
                    string filePath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
    
                    if (!filePath.EndsWith("\\"))
                        filePath += "\\owf";
                    else
                        filePath += "owf";
    
                    if (!Directory.Exists(filePath))
                        Directory.CreateDirectory(filePath);
    
                    filePath += "\\Log.txt";
    
                    lock (syncContoller)
                    {
                        using (StreamWriter sw = new StreamWriter(filePath, true))
                        {
                            sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.sss") + "\t" + message);
                        }
                    }
                }
            }
        }
    }
    
    Hosam Aly : Thanks, but that's not what I was asking about. I'm opening a simple file to write on it. Now when Excel opens the same file for reading my application fails to write to it, because *Excel* locked it. I'm wondering why.
  • Did you found any solution to this problem? It seems that i have the exact same issue..

    Hosam Aly : I cannot actually replicate it at home, since my home machine has Windows Vista with Excel 2007 installed, and the issue does not occur in my setup. So unfortunately no! If you find one, I would be thankful if you tell me!
  • I believe I'm having the same type of locking issue, reproduced as follows:

    User 1 opens Excel2007 file from network (read-write) (WindowsServer, version unkn). User 2 opens same Excel file (opens as ReadOnly, of course). User 1 successfully saves file many times At some point, User 1 is UNABLE to save the file due to message saying "file is locked". Close down User 2's ReadOnly version...lock is released, and User 1 can now save again.

    How could opening the file in ReadOnly mode put a lock on that file?

    So, it seems to be either an Excel2007 issue, or a server issue.

  • This seems like a .NET issue. (Well; a Bug if you ask me).

    Basically I have replicated the problem by using the following multi-threaded code:

      Dim FS As System.IO.FileStream
      Dim BR As System.IO.BinaryReader
    
      Dim FileBuffer(-1) As Byte
    
      If System.IO.File.Exists(FileName) Then
       Try
        FS = New System.IO.FileStream(FileName, System.IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read)
        BR = New System.IO.BinaryReader(FS)
    
        Do While FS.Position < FS.Length
         FileBuffer = BR.ReadBytes(&H10000)
    
         If FileBuffer.Length > 0 Then
          ... do something with the file here... 
         End If
        Loop
    
        BR.Close()
        FS.Close()
    
       Catch
        ErrorMessage = "Error(" & Err.Number & ") while reading file:" & Err.Description
       End Try
    


    Basically, the bug is that trying to READ the file with all different share-modes (READ, WRITE, READ_WRITE) have absolutely no effect on the file locking, no matter what you try; you would always end up in the same result: The is LOCKED and not available for any other user.

    Microsoft won't even admit to this problem.

    The solution is to use the internal Kernel32 CreateFile APIs to get the proper access done as this would ensure that the OS LISTENs to your request when requesting to read files with a share-locked or locked access.

0 comments:

Post a Comment