Delete an "in use" file after no processes reference it - c#

Searched a lot, but without luck - so here goes
My C# winforms application creates temp files which are opened using the default registered application (let's call them viewer apps). Once the user is done viewing those files, I want to delete them.
Currently, I register for an Application.ApplicationExit event, to delete the file. This approach covers most of the situations but not all. Sometimes the user still has the viewing application open while exiting my app, so the success of my File.Delete depends on whether the viewer has opened the file with FileShare.Delete or not - which is out of my control.
This is what I have found so far, but fall short of what I want
FileOptions.DeleteOnClose does not help, since my app will already be closed in some cases and the temp file will still be needed. Also, when I create the file like this: new FileStream(fn, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete, 4096, FileOptions.DeleteOnClose), the viewer apps like say adobe reader & notepad, still complain about file in use by my application The process cannot access the file because it is being used by another process
MoveFileEx with MOVEFILE_DELAY_UNTIL_REBOOT dwFlags works, but it would wait till a reboot to delete it - I would rather have it deleted once the use is done, since reboots can be few and far between and forcing reboots IMO is not the most user friendly approach. On a side note, does windows automatically clear the %temp% folder on restart? Or is there any temp folder that windows automatically clears on restart?
I can write another background process which constantly tries to delete the temp files till it succeeds, but I would like to avoid deploying one more piece of software to accomplish this. It can be done using a windows service or scheduled task or adding command line switches to my existing app and making it run in "delete mode" in background or through task scheduler. All of it decrease my ease of deployment and use along with increasing my footprint on client's computer
In a nutshell, I am wondering if there is any Win32 API or .NET Framework API that will delete a file as soon as there are no processes with open handle to that file?
EDIT:
The information in the temp files are reasonably private (think your downloaded bank account statements) and hence the need for immediate deletion after viewing as opposed to waiting for a reboot or app restart
Summary of all Answers and Comments
After doing some more experiments with inputs from Scott Chamberlain's answer, and other comments on this question, the best path seems to be to force the end users to close the viewer app before closing my application, if the viewer app disallows deletion (FileShare.Delete) of the temp file. The below factors played a role in the decision
The best option is FileOptions.DeleteOnClose, but this only works if all files open before or after this call use FileShare.Delete option to open the file.
Viewer apps can frequently open files without FileShare.Delete option.
Some viewers close the handle immediately after reading/displaying the file contents (like notepad), whereas some other apps (like Adobe Reader) retain such handle till the file is closed in the viewer
Keeping sensitive files on disk for any longer than required is definitely not a good way to proceed. So waiting till reboot should only be used as a fail-safe and not as the main strategy.
The costs of maintaining another process to do the temp file cleanup, far exceeds the slight user inconvenience when they are forced to "close" the viewer before proceeding further.

This answer is based on my comments in the question.
Try write the file without the delete, close the file, let the editor open the file, then open a new filestream as a read with DeleteOnClose with an empty body in the using section.
If that 2nd opening does not fail it will behave exactly like you wanted, it will delete the file as soon as there are no processes with open handle to that file. If the 2nd opening for the delete does fail you can use MoveFileEx as a fallback failsafe.

Related

How to programmatically determine which process created a file in .net?

There are several threads on SO that describe how to check which application creates a file with tools like Sysinternals process monitor. Is something like this possible programmatically from .net?
Background: My program has to remote-control a proprietary third party application using its automation interface, and one of the functions I need from this application has a bug where it creates a bunch of temporary files in %TEMP% that are called tmpXXXX.tmp (the same as .net's Path.GetTempFileName() does) but does not delete them. This causes the C drive to become full over time, eventually failing the application. I already filed a bug to the manufacturer, but we need a temporary workaround for the time being, so I thought of putting a FileSystemWatcher on %TEMP% that watches tmp*.tmp, collects these files, and after the operation on the third-party application finishes, deletes them. But this is risky as another application might also write files with the same file name pattern to %TEMP% so I only want to delete those created by NastyBuggyThirdPartyApplication.exe.
Is this anyhow possible?
This kind of things is possible, but maybe a bit tricky.
To know who created the file, look at the user that owns it. Therefore you might need to create a specific user, and that application will run under this specific user. In order to do that, you need to create a small application that will start your buggy app by impersonating another user, so anything done within the app will be under this user so as file creating...
I don't know how to monitor and get triggered when a file is created, but nothing can prevent you from setting a timer that wakes up every five or ten minutes, then checks if any file in the directory is owned by the application user and closed, so it deletes it.
Maybe if they react fast for this bug fixing, you won't need your app very long time. So another solution, if possible might just to change the Temp folder into another drive, which has lots of space...
One solution is that you use a FileWatcher to automatically delete all the files but before deleting you should check if the file is not currently locked or used by other process, for example the Sysinternal Suite has a tool called handle.exe that can do this. Use it from the command line:
handle.exe -a
You can invoke this from a c# program (there might be some performance issues though)
So what you would do is when a file is created you verify if it is in use or locked (for example u can use the code provided in Is there a way to check if a file is in use?) and then delete it.
Most of the time when an app is using a temp file it will lock it to prevent just what you fear, that you might delete files from other processes.
As far as I can tell there is no sure way to identify which process created a specific file.

Get username of user who has file open on network drive - Microsoft Office Style

I would like to add user friendly file locking to a software running under Windows (Windows 7 mostly), written in C#.
I already achieved the file locking part, by keeping the files in use "open" in the corresponding process. What I now still would like to add is recognition of the user who has a file currently open/locked.
The files being accessed lie on a mapped network drive, used by different users on different computers.
When a file is locked and a second person tries to open the file, he should be confronted with a dialog, similar to the "File in use"-dialog from the Microsoft Office programs. There, also the name of the user, currently editing the file, is displayed.
I found solutions to find out the processes, which have a certain file open (used this one: How do I find out which process is locking a file using .NET?)
and I'm also able to read the name of the user who created this process out of it. However, when opening a locked file on a network drive, the username yielded by doing it like this, is always my own one, instead of the one from the user locking the file.
Does anyone have an idea how one could achieve this? I mean Microsoft Office somehow can do this on my same PC with the same user permissions, too. I just'd like to know how...
Cheers!
Office uses a very simple technique, I'll talk about it in .NET terms. Whenever an Office app opens a document file, using FileShare.None, it also creates a hidden "lock-file" with a name that's based on the document file (say, with ".lockfile" appended). And writes Environment.UserDomainName into that file. The file is created with FileOptions.DeleteOnClose and FileShare.Read and kept open as long as the document file is open.
It closes the lock-file when the document is closed again. Using FileOptions.DeleteOnClose ensures that the lock-file disappears even when the program bombs.
When opening the file produces a locking violation, it goes looking for the lock-file and reads the user name. Easy peasy, simple to implement yourself. But can of course only work if it is one particular app that opens the file.

Does copying a file cause it to lock

On web server, I have an ASP.NET website with error.txt inside it.
This file always gets written to. And it is in the bin folder.
Should I be concerned if:
I go to web server and open the bin folder
Go to web server and open the error.txt
My C# code always writes to it in a share mode FileShare.ReadWrite
Is copying the file to another folder using command prompt safer to avoid locking?
It depends on the application you are opening it with. For instance, if you open it with Microsoft Word, it will lock the file and other processes will only be able to read it. However, if you open it with Notepad, the file is not locked and another process can read, write, delete, move, or rename it.
You can test simply by opening a file with the application, and then try to delete, rename, write to, or move the file. If you can perform any of those actions then you know that your application did not lock it.
Assuming you are just copying it with Explorer, copying the file will lock it for the time it takes to read the file. If it is a small file, this will just be a very few milliseconds.
To ensure that your application doesn't crash if it tries to write to the file while it is locked, put the write operation(s) in a loop that retry if an exception is returned, with a 100 ms wait between tries.

How to Copy a File that is In Use

I want to provide my users with the ability to post a log file onto my server rather than requiring them to find it and email it to me.
I am using this library http://ftplib.codeplex.com/ to open an ftp session on the server and send the file. There is a bit of renaming involved but that is it.
Unfortunately the log file to be sent is actually open so I got a 'file is being used by another process' exception. This makes sense when I think about it in so far as the log is open while my app is running. I closed it but, of course, uploading is a long process. I put the upload code into a background thread so that the user may continue. However the log cannot be re-opened until the upload is complete. In the meantime there could be some event that should be written to the log.
So I am looking for a way to copy the log and then upload it. What would be the best way to do that? The log is a binary file BTW.
If you don't own the code that has the log file open (ie, it's another app or a closed source dll), you can try doing a File.Copy(<log>, <tempdest>) and send that file, deleting it when you're done. This only sometimes works when you don't have read access to the file.
If you do own the code that is accessing the file in the first place, you want to open it with an explicit ShareMode ie
File.Open(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read)

Is there a way in c# to know when the user has finished editing a file with an application?

This is what I'm trying to do :
Download a file (txt, doc, xls, whatever) from a server
Open the file with the appropriate application using System.Diagnostics.Process.Start(path to file)
Monitor for file changes using a FileSystemWatcher.
Each time the file is changed, upload the file back to the server
Continue monitoring until the user has finished editing the file
Delete the local copy of the file
Exit the application
I'm stuck at step 5. How can I know whether a user has finished working on a file ?
I cannot rely on the file being locked (notepad doesn't lock txt files for example).
I cannot rely on a process having exited or not (an example is Notepad++ for txt files : the file could be open in a tab. When you close the tab, you've finished editing the file, but the process is still running)
Any idea/points on how to do that in C# ?
You've excluded the two ways you could go about detecting the file being in use: file locking, and the process you start exiting.
The only alternative I an think of is to display a dialog to ask the user when they've finished editing.
Edit: For what it's worth - FileZilla has this type of behaviour. You can choose to edit a file on the remote server, it downloads the file, launches the default editor, and (in the background) shows a "If you've finished editing - Click OK" button.
This gives me the opportunity to cancel an edit, if I've mucked up the file and saved it.
This is really hard to do - we've tried various things but never found anything that was foolproof. If you know the program you have launched then, in theory, you can find the file handles it uses and see when it stops using the one you're interested in.....but if you rely on Windows to resolve the default application to launch even this becomes tricky.
We copy editable files into a temp folder named with the date and rely on users uploading them back when they have finished their edit session. We then clean up previous days folders on application startup.
You could check the date of last change of the file. This date gets set when you save changes to the file. Mind though that this field is not very reliable since one can set it to any value (with appropriate tools).

Categories