Wait until the file is completely written

When a file is created ( FileSystemWatcher_Created ) in one directory, I copy it to another. But when I create a large file (> 10 MB), it cannot copy the file because it starts to copy already when the file is not finished yet, creating ...
This causes the file cannot be copied because it is being used by another process .; (
Any help?

 class Program { static void Main(string[] args) { string path = @"D:\levan\FolderListenerTest\ListenedFolder"; FileSystemWatcher listener; listener = new FileSystemWatcher(path); listener.Created += new FileSystemEventHandler(listener_Created); listener.EnableRaisingEvents = true; while (Console.ReadLine() != "exit") ; } public static void listener_Created(object sender, FileSystemEventArgs e) { Console.WriteLine ( "File Created:\n" + "ChangeType: " + e.ChangeType + "\nName: " + e.Name + "\nFullPath: " + e.FullPath ); File.Copy(e.FullPath, @"D:\levan\FolderListenerTest\CopiedFilesFolder\" + e.Name); Console.Read(); } } 
+46
c # file filesystems io copy
Jun 11 2018-12-12T00:
source share
9 answers

There is only a workaround for the problem you are facing.

Before starting the copy process, check if the file is running. You can call the following function until you get the value False.

1st method copied directly from this answer :

 private bool IsFileLocked(FileInfo file) { FileStream stream = null; try { stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None); } catch (IOException) { //the file is unavailable because it is: //still being written to //or being processed by another thread //or does not exist (has already been processed) return true; } finally { if (stream != null) stream.Close(); } //file is not locked return false; } 

Second method:

 const int ERROR_SHARING_VIOLATION = 32; const int ERROR_LOCK_VIOLATION = 33; private bool IsFileLocked(string file) { //check that problem is not in destination file if (File.Exists(file) == true) { FileStream stream = null; try { stream = File.Open(file, FileMode.Open, FileAccess.ReadWrite, FileShare.None); } catch (Exception ex2) { //_log.WriteLog(ex2, "Error in checking whether file is locked " + file); int errorCode = Marshal.GetHRForException(ex2) & ((1 << 16) - 1); if ((ex2 is IOException) && (errorCode == ERROR_SHARING_VIOLATION || errorCode == ERROR_LOCK_VIOLATION)) { return true; } } finally { if (stream != null) stream.Close(); } } return false; } 
+32
Jun 11 2018-12-12T00:
source share

From the documentation for FileSystemWatcher :

The OnCreated event is OnCreated as soon as a file is created. If the file is copied or transferred to the watched directory, the OnCreated event will be immediately raised, followed by one or more OnChanged events.

So, if the copy fails (catch exception), add it to the list of files that still need to be migrated, and try the copy during the OnChanged event. In the end, it should work.

Something like (incomplete, catch certain exceptions, initialize variables, etc.):

  public static void listener_Created(object sender, FileSystemEventArgs e) { Console.WriteLine ( "File Created:\n" + "ChangeType: " + e.ChangeType + "\nName: " + e.Name + "\nFullPath: " + e.FullPath ); try { File.Copy(e.FullPath, @"D:\levani\FolderListenerTest\CopiedFilesFolder\" + e.Name); } catch { _waitingForClose.Add(e.FullPath); } Console.Read(); } public static void listener_Changed(object sender, FileSystemEventArgs e) { if (_waitingForClose.Contains(e.FullPath)) { try { File.Copy(...); _waitingForClose.Remove(e.FullPath); } catch {} } } 
+7
Jun 11 2018-12-12T00:
source share

This is an old thread, but I will add information for other people.

I had a similar problem with a program that writes PDF files, sometimes it takes 30 seconds to render. This is the same period that my watcher_FileCreated class waits before copying a file.

Files were not locked.

In this case, I checked the size of the PDF file, and then waited 2 seconds before comparing the new size, if they were unequal, the stream would sleep for 30 seconds and try again.

+6
May 20 '15 at 2:24
source share

You are really lucky - the program that writes the file blocks it, so you cannot open it. If he hadn’t blocked it, you would have copied the partial file without having any problems with this.

If you cannot access the file, you can assume that it is still in use (even better - try opening it in exclusive mode and see if anyone else opens in it, instead of guessing because of a file failure Copy). If the file is locked, you will have to copy it at another time. If it is not blocked, you can copy it (there is little potential for the state of the race).

When is the "other time"? I don’t remember when FileSystemWatcher sends several events to a file - check this, you may just need to ignore the event and wait for another one. If not, you can always set the time and double-check the file in 5 seconds.

+4
Jun 11 2018-12-12T00:
source share

Well, you yourself give the answer; you need to wait until the file is created. One way to do this is to check if the file is saved. An example of this can be found here: Is there a way to check if a file is being used?

Please note that you will have to modify this code to work in your situation. You might want to have something like (pseudocode):

 public static void listener_Created() { while CheckFileInUse() wait 1000 milliseconds CopyFile() } 

Obviously, you should protect yourself from endless while if the owner’s application never releases the lock. Also, it might be worth checking out other events from FileSystemWatcher that you can subscribe to. There may be an event that you can use to get around this problem.

+2
Jun 11 2018-12-12T00:
source share

So, quickly looking through some of these and other similar questions, I went on a fun goose chase this afternoon, trying to solve the problem with two separate programs, using the file as a synchronization method (as well as saving the file). A bit unusual situation, but it definitely highlighted for me problems with "checking if the file is locked, and then open it if it doesn't fit."

The problem is this: the file may become locked between the time it was checked and the time you actually open the file. It is really difficult to track sporadic. It is impossible to copy a file because it is used by another process if you are not looking for it either.

The main permission is simply to try to open the file inside the catch block, so if you lock it, you can try again. Thus, there is no time between verification and opening; the operating system does this at the same time.

This code uses File.Copy, but it works just as well with any of the static methods of the File class: File.Open, File.ReadAllText, File.WriteAllText, etc.

 /// <param name="timeout">how long to keep trying in milliseconds</param> static void safeCopy(string src, string dst, int timeout) { while (timeout > 0) { try { File.Copy(src, dst); //don't forget to either return from the function or break out fo the while loop break; } catch (IOException) { //you could do the sleep in here, but its probably a good idea to exit the error handler as soon as possible } Thread.Sleep(100); //if its a very long wait this will acumulate very small errors. //For most things it probably fine, but if you need precision over a long time span, consider // using some sort of timer or DateTime.Now as a better alternative timeout -= 100; } } 

Another small note about parallelism: This is a synchronous method that will block the stream both while waiting and when working on the stream. This is the easiest approach, but if the file remains locked for a long time, your program may stop responding. Parellelism is just too much for in-depth study here (and the number of ways you could configure it with asynchronous read / write is ridiculous), but here is one way that it can be parellelized.

 public class FileEx { public static async void CopyWaitAsync(string src, string dst, int timeout, Action doWhenDone) { while (timeout > 0) { try { File.Copy(src, dst); doWhenDone(); break; } catch (IOException) { } await Task.Delay(100); timeout -= 100; } } public static async Task<string> ReadAllTextWaitAsync(string filePath, int timeout) { while (timeout > 0) { try { return File.ReadAllText(filePath); } catch (IOException) { } await Task.Delay(100); timeout -= 100; } return ""; } public static async void WriteAllTextWaitAsync(string filePath, string contents, int timeout) { while (timeout > 0) { try { File.WriteAllText(filePath, contents); return; } catch (IOException) { } await Task.Delay(100); timeout -= 100; } } } 

And here is how to use it:

 public static void Main() { test_FileEx(); Console.WriteLine("Me First!"); } public static async void test_FileEx() { await Task.Delay(1); //you can do this, but it gives a compiler warning because it can potentially return immediately without finishing the copy //As a side note, if the file is not locked this will not return until the copy operation completes. Async functions run synchronously //until the first 'await'. See the documentation for async: https://msdn.microsoft.com/en-us/library/hh156513.aspx CopyWaitAsync("file1.txt", "file1.bat", 1000); //this is the normal way of using this kind of async function. Execution of the following lines will always occur AFTER the copy finishes await CopyWaitAsync("file1.txt", "file1.readme", 1000); Console.WriteLine("file1.txt copied to file1.readme"); //The following line doesn't cause a compiler error, but it doesn't make any sense either. ReadAllTextWaitAsync("file1.readme", 1000); //To get the return value of the function, you have to use this function with the await keyword string text = await ReadAllTextWaitAsync("file1.readme", 1000); Console.WriteLine("file1.readme says: " + text); } //Output: //Me First! //file1.txt copied to file1.readme //file1.readme says: Text to be duplicated! 
+1
Jan 06 '17 at 2:26
source share

You can use the following code to check if a file can be opened with exclusive access (that is, it cannot be opened by another application). If the file is not closed, you can wait a few seconds and check again until the file is closed, and you can safely copy it.

You still have to check if File.Copy worked, because another application may open the file between the moment the file was checked and the moment it was copied.

 public static bool IsFileClosed(string filename) { try { using (var inputStream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.None)) { return true; } } catch (IOException) { return false; } } 
0
Jun 11 2018-12-12T00:
source share

When a file is written in binary format (byte by byte), create a FileStream and the above solution Does not work, because the file is ready and wrotted in each byte, so in this situation you will need another workaround: Do this when the file is created or you want to start file processing

 long fileSize = 0; currentFile = new FileInfo(path); while (fileSize < currentFile.Length)//check size is stable or increased { fileSize = currentFile.Length;//get current size System.Threading.Thread.Sleep(500);//wait a moment for processing copy currentFile.Refresh();//refresh length value } //Now file is ready for any process! 
0
Nov 15 '16 at 13:24
source share

I would like to add an answer here because it worked for me. I used time delays, while loops, all I could think of.

I got a windows explorer window open output folder. I closed it, and everything worked like a charm.

I hope this helps someone.

-2
Jul 30 '15 at 12:47
source share



All Articles