0

What I'm doing

I'm working on a webservice which is copying files from one location to another. Files are being updated(the size should be increased every 3 seconds since there is text added).

1st option:

I'm checking every 10 seconds if any of the files is modified(they are being modified every 5 seconds cca) so I can copy(and overwrite) them to the final destination. Atm I'm using a code which is comparing the last edit time of the file with actual time - some amount of time(1 minute atm).

DateTime lastEditTime = new DateTime();
lastEditTime = File.GetLastWriteTime(myFile);

if (lastEditTime > DateTime.Now.AddMinutes(-1)) 
{
     File.Copy(myFile, newFileName, true);
}

But I think this is kinda bad approach since there might be some time space or something and I won't get some changes.

2nd option

I could check the file sizes(using the FileInfo.Length property probably) of each file in the source directory and compare them to the ones in final destination. This should be ok too since the file sizes should only grow since the text is added only.

3rd option

I read a lot people recommend the FileSystemWatcher but I don't want to miss some changes which might happen - at least I read that at other SO questions(see https://stackoverflow.com/a/240008/2296407).

What is my question?

What is the best option to know if any file was changed(if the file in source is different from file in final destination) in last x mins or seconds cause I don't want to copy everything since there might be a lot of files. By being best option I mean: is it faster to compare each files sizes or compare the File.GetLastWriteTime(myFile) with actual time - some time. In the second case ther is also question: How big the time span should be? If I put a big time span I will probably copy more files than I actually need but if I put it low I might miss some changes.

If you have some better options feel free to share them with me!

Community
  • 1
  • 1
Ms. Nobody
  • 1,219
  • 3
  • 14
  • 34
  • FileSystemWatcher. You won't miss any changes when you use it, because he notifies you about a change. – user743414 Jul 16 '14 at 11:32
  • 1
    @user743414: Ms. Nobody is talking about a known problem with buffer overflow errors in the `FileSystemWatcher`, which can result in file change events not being thrown. See my answer about this. – Jens H Jul 16 '14 at 11:47

1 Answers1

1

Although you already mentioned it in your option 3, I still think should give it a try with the FileSystemWatcher Class. As far as I understood you, you have not yet done so, right?

Although it is true that the watcher may lose some event in the default configuration, you can still make it work reliably if you do some tweaking.

Have a look at the "Remarks" section in the documentation (highlights by me):

The Windows operating system notifies your component of file changes in a buffer created by the FileSystemWatcher. If there are many changes in a short time, the buffer can overflow. This causes the component to lose track of changes in the directory, and it will only provide blanket notification. Increasing the size of the buffer with the InternalBufferSize property is expensive, as it comes from non-paged memory that cannot be swapped out to disk, so keep the buffer as small yet large enough to not miss any file change events. To avoid a buffer overflow, use the NotifyFilter and IncludeSubdirectories properties so you can filter out unwanted change notifications.

Things you can do to make it reliably work:

Note that a FileSystemWatcher may miss an event when the buffer size is exceeded. To avoid missing events, follow these guidelines:

  • Increase the buffer size by setting the InternalBufferSize property.
  • Avoid watching files with long file names, because a long file name contributes to filling up the buffer. Consider renaming these files using shorter names.
  • Keep your event handling code as short as possible.

For example user Nomix says he raised the buffer size (property InternalBufferSize) up to 16 MB and has never had a problem with the FileSystemWatcher class (SO post is here.) And I can confirm this with a project in my company that works fine for years, too, since we found out about the buffer.

Initialization of the object might look like this for example:

private void InitWatcher()
{
    // Create a new FileSystemWatcher and set its properties.
    FileSystemWatcher watcher = new FileSystemWatcher();
    watcher.Path = "Your path to watch";

    // You only want to watch a single folder
    watcher.IncludeSubdirectories = false;

    // You mentioned both LastWrite and Size
    // You can combine them or just watch for only a specific property
    // Simply configure it to your needs
    watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size

    // Only watch text files.
    watcher.Filter = "*.txt";

    // Add event handlers, omit those you are not interested in
    watcher.Changed += new FileSystemEventHandler(OnChanged);

    // Begin watching.
    watcher.EnableRaisingEvents = true;
}

You can then subscribe to those events that are of interest for you, like the Changed event and react to it as easy as:

private static void OnChanged(object source, FileSystemEventArgs e)
{
   File.Copy(e.FullPath, newFileName, true);
}
Community
  • 1
  • 1
Jens H
  • 4,590
  • 2
  • 25
  • 35
  • I'm just wondering what exactly "many changes in a short time" mean. Do you think that change in one of the files every 3 seconds might be problem with buffer? I'm just kinda scared of it, that's all. But I guess I should give it a try then do it my ways.. – Ms. Nobody Jul 16 '14 at 11:53
  • Btw should I use "use the NotifyFilter and IncludeSubdirectories" even when I have all files I care about in one directory? + Sorry for maybe stupid questions but when it comes to problems with memory I'm running away.. – Ms. Nobody Jul 16 '14 at 11:54
  • @Ms.Nobody: Regard the "many changes in short time" as just a vague wording by Microsoft as it will be unpredictable and is depending on each indiviual system configuration. You might as well find that your specific scenario is running fine just as it is. Have a try and see for yourself. And yes, I would configure the `NotifyFilter`. See it as a whitelist with the purpose to tell the watcher to **only** do things I **need** and nothing else." The more properties it needs to watch the more overhead it has to handle => Keep overhead as low as possible. – Jens H Jul 16 '14 at 12:04
  • Ok, I will try and give you some feedback(accept answer etc) tomorrow. Thanks for your time! – Ms. Nobody Jul 16 '14 at 12:06
  • The FileSystemWatcher uses this api function: http://msdn.microsoft.com/en-us/library/aa365465%28VS.85%29.aspx Like the docs for ReadDirectoryChangesW and FileSystemWatcher are saying the buffer must not exceed 64KB. So setting it to 16MB in FileSystemWatcher will maybe use internal a much smaller buffer. I think they will fall back to 8KB. So the docs say each event can be up to 16 bytes, witout the file name. MAX_PATH is declared as 260 bytes. So each event can be up to 276 bytes in size, including filename. A 8192 Bytes default buffer can handle at least 29 events at once. – user743414 Jul 17 '14 at 09:58
  • Comments are too small. :) On my system I have no path which is longer than 100 bytes, so the default buffer can handle up to 70 events at once. And "at once" means a very very very shor time. :) – user743414 Jul 17 '14 at 09:59