title: c# Unable to open file for reading
body: <p>I'm writing a program that uses <code>FileSystemWatcher</code> to monitor changes to a given directory, and when it receives OnCreated or OnChanged event, it copies those created/changed files to a specified directories. At first I had problems with the fact that OnChanged/OnCreated events can be sent twice (not acceptable in case it needed to process 500MB file) but I made a way around this and with what I'm REALLY BLOCKED with is getting the following <code>IOException</code>:
      The process cannot access the file 'C:\Where are Photos\bookmarks (11).html' because it is being used by another process.</p>
  
  <p>Thus, preventing the program from copying all the files it should.
      So as I mentioned, when user uses this program he/she specifes monitored directory, when user copies/creates/changes file in that directory, program should get OnCreated/OnChanged event and then copy that file to few other directories.
      Above error happens in all cases, if user copies few files that needs to overwrite other ones in folder being monitored or when copying bulk of several files or even sometimes when copying one file in a monitored directory.
      Whole program is quite big so I'm sending the most important parts.
  OnCreated:</p>
  
  <pre><code>private void OnCreated(object source, FileSystemEventArgs e) {
          AddLogEntry(e.FullPath, "created", "");
  
          // Update last access data if it's file so the same file doesn't
          // get processed twice because of sending another event.
          if (fileType(e.FullPath) == 2) {
              lastPath = e.FullPath;
              lastTime = DateTime.Now;
          }
  
          // serves no purpose now, it will be remove soon
          string fileName = GetFileName(e.FullPath);
  
          // copies file from source to few other directories
          Copy(e.FullPath, fileName);
  
          Console.WriteLine("OnCreated: " + e.FullPath);
  }
  </code></pre>
  
  <p>OnChanged:</p>
  
  <pre><code>private void OnChanged(object source, FileSystemEventArgs e) {
      // is it directory
      if (fileType(e.FullPath) == 1)
          return; // don't mind directory changes itself
  
      // Only if enough time has passed or if it's some other file
      // because two events can be generated
      int timeDiff = ((TimeSpan)(DateTime.Now - lastTime)).Seconds;
      if ((timeDiff &lt; minSecsDiff) &amp;&amp; (e.FullPath.Equals(lastPath))) {
          Console.WriteLine("-- skipped -- {0}, timediff: {1}", e.FullPath, timeDiff);
          return;
      }
  
      // Update last access data for above to work
      lastPath = e.FullPath;
      lastTime = DateTime.Now;
  
      // Only if size is changed, the rest will handle other handlers
      if (e.ChangeType == WatcherChangeTypes.Changed) {
          AddLogEntry(e.FullPath, "changed", "");
          string fileName = GetFileName(e.FullPath);
          Copy(e.FullPath, fileName);
  
          Console.WriteLine("OnChanged: " + e.FullPath);
      }
  }
  </code></pre>
  
  <p>fileType:</p>
  
  <pre><code>private int fileType(string path) {
      if (Directory.Exists(path))
          return 1; // directory
      else if (File.Exists(path))
          return 2; // file
      else
          return 0;
  }
  </code></pre>
  
  <p>Copy:</p>
  
  <pre><code>private void Copy(string srcPath, string fileName) {
      foreach (string dstDirectoy in paths) {
          string eventType = "copied";
          string error = "noerror";
          string path = "";
          string dirPortion = "";
  
          // in case directory needs to be made
          if (srcPath.Length &gt; fsw.Path.Length) {
              path = srcPath.Substring(fsw.Path.Length,
                      srcPath.Length - fsw.Path.Length);
  
              int pos = path.LastIndexOf('\\');
              if (pos != -1)
                  dirPortion = path.Substring(0, pos);
          }
  
          if (fileType(srcPath) == 1) {
              try {
                  Directory.CreateDirectory(dstDirectoy + path);
                  //Directory.CreateDirectory(dstDirectoy + fileName);
                  eventType = "created";
              } catch (IOException e) {
                  eventType = "error";
                  error = e.Message;
              }
          } else {
              try {
                  if (!overwriteFile &amp;&amp; File.Exists(dstDirectoy + path))
                      continue;
  
                  // create new dir anyway even if it exists just to be sure
                  Directory.CreateDirectory(dstDirectoy + dirPortion);
  
                  // copy file from where event occured to all specified directories
                  using (FileStream fsin = new FileStream(srcPath, FileMode.Open, FileAccess.Read, FileShare.Read)) {
                      using (FileStream fsout = new FileStream(dstDirectoy + path, FileMode.Create, FileAccess.Write)) {
                          byte[] buffer = new byte[32768];
                          int bytesRead = -1;
  
                          while ((bytesRead = fsin.Read(buffer, 0, buffer.Length)) &gt; 0)
                              fsout.Write(buffer, 0, bytesRead);
                      }
                  }
  
              } catch (Exception e) {
                  if ((e is IOException) &amp;&amp; (overwriteFile == false)) {
                      eventType = "skipped";
                  } else {
                          eventType = "error";
                          error = e.Message;
                          // attempt to find and kill the process locking the file.
                          // failed, miserably
                          System.Diagnostics.Process tool = new System.Diagnostics.Process();
                          tool.StartInfo.FileName = "handle.exe";
                          tool.StartInfo.Arguments = "\"" + srcPath + "\"";
                          tool.StartInfo.UseShellExecute = false;
                          tool.StartInfo.RedirectStandardOutput = true;
                          tool.Start();
                          tool.WaitForExit();
                          string outputTool = tool.StandardOutput.ReadToEnd();
                          string matchPattern = @"(?&lt;=\s+pid:\s+)\b(\d+)\b(?=\s+)";
                          foreach (Match match in Regex.Matches(outputTool, matchPattern)) {
                              System.Diagnostics.Process.GetProcessById(int.Parse(match.Value)).Kill();
                          }
  
                          Console.WriteLine("ERROR: {0}: [ {1} ]", e.Message, srcPath);
                  }
              }
          }
  
          AddLogEntry(dstDirectoy + path, eventType, error);
      }
  }
  </code></pre>
  
  <p>I checked everywhere in my program and whenever I use some file I use it in <code>using</code> block so even writing event to log (class for what I omitted since there is probably too much code already in post) wont lock the file, that is it shouldn't since all operations are using <code>using</code> statement block.</p>
  
  <p>I simply have no clue who's locking the file if not my program "copy" process from user through Windows or something else.</p>
  
  <p>Right now I have two possible "solutions" (I can't say they are clean solutions since they are hacks and as such not desirable). Since probably the problem is with <code>fileType</code> method (what else could lock the file?) I tried changing it to this, to simulate "blocking-until-ready-to-open" operation:</p>
  
  <p>fileType:</p>
  
  <pre><code>private int fileType(string path) {
      FileStream fs = null;
      int ret = 0;
      bool run = true;
  
      if (Directory.Exists(path))
          ret = 1;
      else {
          while (run) {
              try {
                  fs = new FileStream(path, FileMode.Open);
                  ret = 2;
                  run = false;
              } catch (IOException) {
              } finally {
                  if (fs != null) {
                      fs.Close();
                      fs.Dispose();
                  }
              }
          }
      }
  
      return ret;
  }
  </code></pre>
  
  <p>This is working as much as I could tell (test), but... it's hack, not to mention other deficients.</p>
  
  <p>The other "solution" I could try (I didn't test it yet) is using <code>GC.Collect()</code> somewhere at the end of <code>fileType()</code> method. Maybe even worse "solution" than previous one.</p>
  
  <p>Can someone pleas tell me, what on earth is locking the file, preventing it from opening and how can I fix that? What am I missing to see?</p>
  
  <p>Thanks in advance.</p>