I am trying to delete a file in C#, however I am receiving a message that the file is used from another process. What I want to do is to check if the files exists and close it. I am using the following function in order to check if the file is open:
public static bool IsFileInUse(string path)
{
if (string.IsNullOrEmpty(path))
throw new ArgumentException("'path' cannot be null or empty.", "path");
try
{
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read)) { }
}
catch (IOException)
{
return true;
}
return false;
}
and I am trying when the file is in use to close it:
bool checking = IsFileInUse(file );
File.Create(file ).Close();
if (File.Exists(file))
{
File.Delete(file );
}
I got issues in File.Create line, I am receiving the message:
File is being used by another process.
EDIT: I am trying to use lock approach in order to delete the file. Am I suppose to delete the file inside a lock statement? How Can I use properly the lock statement?
Why do you suppose that a reading operation will fail if file is in use while a writing operation will not? File.Create() will fail exactly as new FileStream() failed before...
See also IOException: The process cannot access the file 'file path' because it is being used by another process.
Note that your check will fail if the other process didn't open that file exclusively (check FileShare enumeration): file may be open for shared reading, writing and sometimes even for deleting (for example you may be able to read concurrently but not writing however the other process may let you delete that file...).
To close an open file can be really disruptive for the other process, it may crash, nicely handle the problem or...anything else (silently ignore that error and produce random output, open file again and so on...) Is it possible to do it in C#? Yes with some P/Invoke...
1) Let's find the handle for the file you want to unlock. Use NtQuerySystemInformation() and enumerate all handles until you find the one that refers to that file.
2) Duplicate that handle to be valid in your own process using DuplicateHandle().
3) Close just create handle specifying DUPLICATE_CLOSE_SOURCE, it will close both your handle and the original one (of course if your process has enough permissions).
4) Check if file is really closed calling NtQuerySystemInformation() again, if not then you may need to directly close its parent process.
In your code, you don't do anything with the IsFileInUse result.
This File.Create(file ).Close(); will also not close a file that is opened by another process. You need to close the process that has the file open, and if it is your own app, close the file handle before trying to delete the file.
bool checking = IsFileInUse(file );
File.Create(file ).Close();
if (!checking)
{
if (File.Exists(file))
{
File.Delete(file );
}
}
You have no need to check if the file exists, just try do delete it:
https://msdn.microsoft.com/en-us/library/system.io.file.delete(v=vs.110).aspx
If the file to be deleted does not exist, no exception is thrown.
Try and check the exception
try {
File.Delete(file);
}
catch (IOException) {
// File in use and can't be deleted; no permission etc.
}
Related
I have the following method to delete a file with a provided path
private void DestroyFile(string path)
{
try
{
if (File.Exists(path))
{
File.Delete(path);
}
if (File.Exists(path))
{
throw new IOException(string.Format("Failed to delete file: '{0}'.", path));
}
}
catch (Exception ex)
{
throw ex;
}
}
I am getting the IOException that is thrown if the file exists after the File.Delete method. Specifically
System.IO.IOException): Failed to delete file: 'C:\Windows\TEMP\[FILE NAME]'.
I have also confirmed that the file does not exist at the location in the path variable after the execution is complete. I am wondering if I am running up against a race condition between the file system updating after File.Delete and checking against it again with File.Exists. Is there a better way to smoothly delete? I know that File.Delete won't return an error if the file doesn't exist so maybe these checks are a bit redundant. Should I check if the file is in use rather than if it exists at all?
Some important additional information:
The program can and does run successfully often but this particular error has been frequently seen recently.
File.Delete will mark file for deletion. File really will be deleted only when all handles to it are closed (if there are no such handles - it will always be deleted after File.Delete returns). As documented for DeleteFile winapi function (which is used by C# File.Delete):
The DeleteFile function marks a file for deletion on close. Therefore,
the file deletion does not occur until the last handle to the file is
closed
Usually there are no open handles to files you delete. Or, if there are open handles - they usually don't have "delete" share (this share allows another process to mark file for deletion), so when you try to delete such file - it either gets deleted (no open handles) or access denied or similar exception is thrown (some handles, but without delete share).
However, sometimes some software, such as antivirus or search indexer, might open arbitrary files with "delete" share and hold them for some time. If you try to delete such file - it will go without errors and file really will be deleted when that software closes its handle. However, File.Exists will return true for such "pending delete" file.
You can reproduce this issue with this simple program:
public class Program {
public static void Main() {
string path = #"G:\tmp\so\tmp.file";
// create file with delete share and don't close handle
var file = new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.Delete);
DestroyFile(path);
GC.KeepAlive(file);
}
private static void DestroyFile(string path) {
try {
if (File.Exists(path)) {
// no error
File.Delete(path);
}
// but still exists
if (File.Exists(path)) {
throw new IOException(string.Format("Failed to delete file: '{0}'.", path));
}
}
catch (Exception ex) {
throw ex;
}
}
}
You can retry File.Exists check forever in the program above - file will exist until you close the handle.
So that's what happens in your case - some program has open handle to this file with FileShare.Delete.
You should expect such situation. For example - just remove that File.Exists check, since you marked file for deletion and it will be deleted anyway.
while its not documented in the API, File.Delete WILL return before the file is completely deleted.
This is why you are running into the case you are having. Delete call will check for all the things that would make the delete fail (existing handle, lock, permission ect) and it will return after the initiation of Delete request
So its relatively safe to just put a while loop right after to wait until the file is gone or use a FileSystemWatcher to watch for Deleted event
File.Delete and generally most methods from System.IO are dependent on filesystem/streams/etc, whom a bit live their own lives, and are not managed resources, hence File.Delete can return before file is physically deleted, but after it's marked for deletion.
After File.Delete returns, you can be sure file will be deleted, if not this method will throw exception by itself, so second check with File.Exists and throwing IOException is unnecessary.
If you want custom exception, catch exceptions from File.Delete.
And in code attached, remember that throw ex; is diffrenent from throw; and changes stack trace to current line.
I have a log file that I delete and create every time my application is launched like so:
if (File.Exists(LogPath))
{
File.Delete(LogPath);
File.Create(LogPath);
}
And I'm writing in it using File.AppendAllText like so:
File.AppendAllText(LogPath, logMessage);
My issue is that when I run the program for the second time, the above call causes an exception to be thrown saying file can't be accessed
"because it is being used by another process"
What is wrong with this approach?
It's caused by File.Create(). Remove it and File.AppendAllText creates a new file if it doesn't exist.
Note:
File.Create() returns a FileStream value, if you do not dispose it, then it will cause an error when you want to access it.
This is not because of File.AppendAllText but instead this line of code:
File.Create(LogPath);
As per the documentation of File.Create(string):
Return Value
Type: System.IO.FileStream
A FileStream that provides read/write access to the file specified in path.
It returns an open FileStream object. You need to dispose of this object in order to close the stream and release the file. If you don't then this object will keep the file open until GC finalizes the object at some later indeterminate point in time.
Here's how to write this line of code, either one of the following two alternatives will work:
File.Create(LogPath).Dispose();
using (File.Create(LogPath)) { }
What happened is that the second time your program ran the file exists, so you deleted it and then recreated it, but the "recreated it" part kept the file open, so when it a short time later reached the File.AppendAllText method, the file was still open.
Note: If you always call File.AppendAllText you can simply just delete it, as AppendAllText will create the file if it doesn't already exist, as per the documentation of File.AppendAllText:
Opens a file, appends the specified string to the file, and then closes the file. If the file does not exist, this method creates a file, writes the specified string to the file, then closes the file.
(my emphasis)
You would need to close the file after you create for further processing.
if (File.Exists(LogPath))
{
File.Delete(LogPath);
using(var handler = File.Create(LogPath))
{
}
}
Other way could be to use WriteAllText and you won't need to delete it everytime.
File.WriteAllText(LogPath, "contents");
You, probably, mean
// clear the file (write an empty text to it) if it exists
if (File.Exists(LogPath))
{
File.WriteAllText(LogPath, "");
}
...
File.AppendAllText(LogPath, logMessage);
you can try combining clearing and writing in one call:
File.WriteAllText(LogPath, logMessage);
If the file exists, WriteAllText will clear it and write logMessage; if file doesn't exist, WriteAllText will create it and write logMessage.
Question background:
I am attempting to overwrite the contents of one specified file with the contents of another specified file within a folder on my C drive using the following 'File.Replace' method:
//'null' has been set to the 'backup file' parameter as I do not need this.
File.Replace(fileOnesLocation, filesTwosLocation, null);
The error:
I have the above method wrapped in a try catch and am currently receiving the following error:
System.IO.IOException: The process cannot access the file
because it is being used by another process.
Can anyone point me in the right direction of whats going wrong here?
If you want to avoid this errors, you could try doing something like this answer, create a method to check whether your file is open or not.
protected virtual 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;
}
If the file is open either by you or another logged in user then you may not be able to open it.
check in task manager for processes by users and close the file.
This error is often caused when the file being replaced or written to is open by you or someone/thing while the code is running.
how to find whether specific .txt file is opened in notepad?
I have tried solutions mentioned here
Is there a way to check if a file is in use?
But they work fine for Word and pdf file but not working for txt file opened in Notepad.
here is code I have wrote.
public bool IsFileOpen(string strFileName)
{
bool retVal = false;
try
{
if (File.Exists(pstrFileName))
{
using (FileStream stream = File.OpenWrite(pstrFileName))
{
try
{
}
catch (IOException)
{
retVal = true;
}
finally
{
stream.Close();
stream.Dispose();
}
}
}
}
catch (IOException)
{ //file is opened at another location
retVal = true;
}
catch (UnauthorizedAccessException)
{ //Bypass this exception since this is due to the file is being set to read-only
}
return retVal;
}
am i missing somthing here.??
My requirement:
I have application which works similar to VSS. When user checks out specific file and opens ,and try to check in the same, while it has opened. Application is suppose to throw a warning message.For that i have used the above functionality.Its working fine for word and pdf.
To expand on my comment. A file is only locked if a handle is kept open by an application. Word for example will open the file, read in the stream and maintain the handle so that other applications cannot delete that file while the user is working on it.
Notepad, and other applications, just open the file, read in the entire stream and then close the file releasing the lock they have. This means that the file is no longer locked and can be edited by another application or even deleted and Notepad will not care as it has its own copy in memory.
You could try and hack around with getting instances of Notepad and checking if a file is open but this is ultimately not a great idea. If the file is not locked then you should be free to do what you want with it.
This is a hack solution I just came up with, but it should work for you. This makes use of System.Diagnostics.
Process[] processes = Process.GetProcessesByName("notepad");
for (int i = 0; i < processes.Length; i++)
{
Console.WriteLine(processes[i].MainWindowTitle);
if (processes[i].MainWindowTitle.Equals("myFile.txt - Notepad"))
{
Console.WriteLine("The file myFile is Open!");
}
}
Console.ReadLine();
Hopefully that should do the trick. My example looks to see if an instance of notepad is open with the window title "myFile.txt - Notepad". The window name is always "filename.extension - Notepad" so you can handle that however you might need to.
I suppose you could make a call to System.IO.File.GetLastAccessTime(filePath). You could then poll the file every so often and when the access time changes you know the file has been opened, you can then fire an event that the file has been opened. See Jeffs post here:
Detect File Read in C#
You could also do this using the following tactic: It seems that notepad does hold some kind of lock on the hosting folder (try to delete the folder and you'll see you can't).
you could use the following code Using C#, how does one figure out what process locked a file? to check list of processes that lock the folder.
one of the processes will be your notepad.
you could them compare by Title as another answers mentioned.
if you're issuing the open of the file - you could save the PID and comapre it with one of the processes that returned.
While calling File.Delete(file_path) for a file which is opened in another process, the attempt fails with cannot access error, but on exiting the app (from where the attempt was made) the file gets deleted automatically. After File.Delete attempt, the path gets inaccessible for any other operation.
I need to either fail on delete and let the path be accessible through the app or delete the file completely, not on app exit.
Well my code is this :
private bool DeleteFilesAsync(string FileToDelete)
{
try
{
//Set file's attribute to normal if it is ReadOnly file
File.SetAttributes(FileToDelete, FileAttributes.Normal);
File.Delete(FileToDelete);
//Some bussiness logic to update file's status in database
return true;
}
catch (Exception ex)
{
//log the error
return false;
}
}
Something wrong here?
Windows does have a delete-on-last-close feature. All deletes are handled that way. The only reason that this almost never occurs in practice is because most apps do not open the file with FILE_SHARE_DELETE so it is not possible to delete a used file. But at the Kernel level all deletes are delete-on-close.
There might be a way to clear the delete flag by calling NtSetInformationFile to set the FileDispositionInfo class. This assumes that it is possible to clear the delete flag. It might well be.
Anyway, a more sane approach would be to open the file before deleting it to ensure that exclusive access is available:
using(new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) { }
After this line passes without exception, we know that the file was unused at the point of opening it. Of course, it might be opened by someone else immediately after this line, but maybe this solution is enough for you.