none
The process cannot access the file - FileSystemWatcher implementation in Windows Service... RRS feed

  • Question

  • Hi,

    I have a windows service that copies pdf files from source machine to destination server path. I have implemented using FileSystemWatcher that listens to the source folder for any file presence. Say if I have 100 files before service is started and then start the service which startes copying the file to destination and then we pump another 500 files to the source folder some times/random some times get below error Message.

    Error:The process cannot access the file because it is being used by another process

    Stack Trace:The process cannot access the file 'C:\TestFolder\Source\abc.pdf' because it is being used by another process.    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)

       at System.IO.File.InternalCopy(String sourceFileName, String destFileName, Boolean overwrite)

       at System.IO.File.Copy(String sourceFileName, String destFileName, Boolean overwrite)

    Sourcemscorlib

     

    Please provide me any suggestion/solution ? Earliest response would be helpful.

     


    Regards Guru

    • Edited by Gururaj B Wednesday, December 28, 2011 9:37 AM
    Wednesday, December 28, 2011 9:34 AM

Answers

  • using System;
    using System.IO;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                FileSystemWatcher fileSystemWatcher = new FileSystemWatcher();
                fileSystemWatcher.Created += new FileSystemEventHandler(fileSystemWatcher_Created);
                fileSystemWatcher.Path = @"C:\Krishnakant";
                fileSystemWatcher.Filter = "*.*";
                fileSystemWatcher.EnableRaisingEvents = true;
    
                Console.WriteLine("Monitoring " + fileSystemWatcher.Path);
    
                Console.ReadLine();
            }
    
            static void fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
            {
                Console.WriteLine("File " + e.FullPath + " started copying : " + DateTime.Now.ToString());
    
                while (true)
                {
                    try
                    {
                        FileStream fileStream = File.Open(e.FullPath, FileMode.Open, FileAccess.Read);
                        Console.WriteLine("File is copied : " + DateTime.Now.ToString());
                        fileStream.Close();
                        //there is the point when the file is completed copying .... now you should be able to access the file and process it.
                        return;
                    }
                    catch (IOException ioException)
                    {
                    }
                }
            }
        }
    }
    
    hope this helps ...

    Regards, Krishnakant This answers, please mark as answered, if this helps please mark as helpful.
    Thursday, December 29, 2011 9:51 AM

All replies

  • Well, what the error message says, the file is used by another process. You're probably getting a file change notification when some process starts writing the pdf file, before it finishes writing.

    The only thing you can do is to handle the exception by retrying the copy operation.

    Wednesday, December 28, 2011 9:42 AM
    Moderator
  • Hi Mike,

     

    Thanks for your response. It helped me reduce getting the error(when checked against the log file I generate getting once for each file than I used to get same error thrice...) when I removed the FileSystemWatcher.Changed event.

    Yes, I am re-trying to copy the file in case of exception.

    But the issue is not completely resolved.

    I even commented FileSystemWatcher.Deleted and FileSystemWatcher.Renamed as I just want an File copy function to invoke when a new file arrives to source folder. Still no luck.

    Regards

    Guru

     


    Regards Guru
    Wednesday, December 28, 2011 1:27 PM
  • If you removed the Changed event then I assume you use only the Created event. That doesn't help much because a file is not created in a single, atomic, operation. Think what happens if you create a file yourself, you would have some code like this:

    FileStream file = File.Create(...);

    while (something) file.Write(...);

    file.Close();

    File.Create will likely be detected by a FileSystemWatcher as a create event. But until the file is closed (and there's not watcher notification for that) the file won't be accessible to another process that tries to copy it.

    So there's not much you can do about this except re-trying the copy until it works.

    How do pdf files arrive in the source folder?

    Wednesday, December 28, 2011 1:38 PM
    Moderator
  • Hi,

    Thanks for the inputs.

    Yes as of now I only have Created and OnError event registered with FileSystemWatcher.

    Yes, I do agree we don't have any flag or status to know when file creation is complete and ready to be copied by other process...what I am looking is like could we lock the file like say use Sync/Monitor class/Lock(){...} mechanism so that hold the file and not allow other process(Copy()) unless the File is completely generated.

    The pdf files are generated by external system(could be UI generated or manually placed as well etc., multiple sources) and will be available in shared location and my service has to copy to required destination when ever file arrives to this Source folder.


    Regards Guru

    • Edited by Gururaj B Wednesday, December 28, 2011 2:47 PM
    Wednesday, December 28, 2011 2:43 PM
  • "what I am looking is like could we lock the file like say use Sync/Monitor class/Lock(){...}"

    Nope, there's nothing like this, especially if you don't have control over the source of the files.

    Wednesday, December 28, 2011 3:10 PM
    Moderator
  • The problem with using the FileSystemWatcher is that it is possible for the same event to fire multiple times. Since they're running Asycrhonously it would be you're own program that's locking the process. I would keep a List<string> of the files that are returned and that you are currently working on (copying or moving). Once the event fires lock the list, check if the file name is already there, if not add it, unlock the list.  If you do find a match in the file name break out of whatever work you're doing. 

    Don't forget to remove the name from the list after.

    It's faster then trying to catch exceptions, since in your model a file in use is not really an unexpected result.

    Wednesday, December 28, 2011 4:03 PM
  • Hi Pantelis,

    Thanks for your views.

    When ever the FileSystemWatcher.Created event is fired what I do is call a method that basically gets me all the files in source folder and push into a Queue and hand over the request to a seperate worker thread which actually does the file copy process.

    string[] sDirFiles = Directory.GetFiles(@"c:\test\", ".pdf");

     foreach (string fileName in sDirFiles)

                {               // Push into queue          }

    Then I start poping the list of files one by one that I had pumped into the queue and initiate the Copy(). Also the Copy functionality gets started when there is atleast 1 file present in the queue.

    And another important point you made was trying to catch for exception is not the solution am looking for as I pretty much know its just matter of time it will happen.

    Also, let me have a thought on your solution.


    Regards Guru
    Thursday, December 29, 2011 8:46 AM
  • using System;
    using System.IO;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                FileSystemWatcher fileSystemWatcher = new FileSystemWatcher();
                fileSystemWatcher.Created += new FileSystemEventHandler(fileSystemWatcher_Created);
                fileSystemWatcher.Path = @"C:\Krishnakant";
                fileSystemWatcher.Filter = "*.*";
                fileSystemWatcher.EnableRaisingEvents = true;
    
                Console.WriteLine("Monitoring " + fileSystemWatcher.Path);
    
                Console.ReadLine();
            }
    
            static void fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
            {
                Console.WriteLine("File " + e.FullPath + " started copying : " + DateTime.Now.ToString());
    
                while (true)
                {
                    try
                    {
                        FileStream fileStream = File.Open(e.FullPath, FileMode.Open, FileAccess.Read);
                        Console.WriteLine("File is copied : " + DateTime.Now.ToString());
                        fileStream.Close();
                        //there is the point when the file is completed copying .... now you should be able to access the file and process it.
                        return;
                    }
                    catch (IOException ioException)
                    {
                    }
                }
            }
        }
    }
    
    hope this helps ...

    Regards, Krishnakant This answers, please mark as answered, if this helps please mark as helpful.
    Thursday, December 29, 2011 9:51 AM