Reputation: 809
I created a simple program to delete temporary files in C# (for fun, not a major project) and am running into locked files (in use) issues. How do you normally either exclude those files? For reference I am receiving the error:
The process cannot access the file 'ExchangePerflog_8484fa31c65c7a31cfcccd43.dat' because it is being used by another process.
Code:
static void Main(string[] args)
{
string folderPath = string.Empty;
folderPath = System.Environment.GetEnvironmentVariable("temp");
deleteFilesInDirectory(folderPath);
}
public static void deleteFilesInDirectory(string folderPath)
{
try
{
var dir = new DirectoryInfo(folderPath);
dir.Attributes = dir.Attributes & ~FileAttributes.ReadOnly;
dir.Delete(true);
MessageBox.Show(folderPath + " has been cleaned.");
}
catch (System.IO.IOException ex)
{
MessageBox.Show(ex.Message);
return;
}
}
Upvotes: 29
Views: 93392
Reputation: 3472
Using dknaack's code. This worked in my case.
FileInfo file = new FileInfo("xyz.txt");
try
{
for (int tries = 0; IsFileLocked(file) && tries < 5; tries++)
Thread.Sleep(1000);
file.Delete();
}
catch (IOException exception)
{
Console.WriteLine(string.Format("File locked: {0}", exception);
}
Upvotes: 3
Reputation: 187
Well I have run into similar problems. When you try to remove directory shortly after removing file you have to force GC to release the file handle from current thread
public void DisposeAfterTest(string filePath)
{
if (File.Exists(filePath))
{
File.Delete(filePath);
}
GC.Collect();
GC.WaitForPendingFinalizers();
if (Directory.Exists(this.TempTestFolderPath))
{
Directory.Delete(this.TempTestFolderPath, true);
}
}
Upvotes: 10
Reputation: 113
The below code will delete the files from a directory and all its sub-directories excluding the locked files and gets the list of the files that are not deleted. You can change the SearchOption to TopDirectoryOnly if you consider only the current directory.
string []files = Directory.GetFiles(dirPath,"*.*", SearchOption.AllDirectories); //this gets the files in all subdirectories as well
List<string> lockedFiles = new List<string>();
foreach(string file in files)
{
try
{
file.Delete();
}
catch (IOException)
{
lockedFiles.Add(file);
}
}
Upvotes: 0
Reputation: 235
Try the following code. Just add two lines before file deletion:
GC.Collect();
GC.WaitForPendingFinalizers();
Upvotes: 16
Reputation: 60556
There is no way to delete a file that is currently in use by another process. But you can wait till the file is not locked.
Check in a while loop till the file is unlocked with this method
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;
}
FileInfo file = new FileInfo("PathToTheFile");
while (IsFileLocked(file))
Thread.Sleep(1000);
file.Delete();
If you want to skip locked files you can do this.
//
var dir = new DirectoryInfo(folderPath);
foreach(var file in dir.GetFiles()) {
try
{
file.Delete();
}
catch (IOException)
{
//file is currently locked
}
}
Upvotes: 23
Reputation: 15091
I don't believe there is any way you can know in advance if the file is in use or not. You could try to get an exclusive lock on the file; but then you'd just be trading one exception for another.
If these are files you are opening, see if you can't do a better job of closing them. If it's more complicated than that - you could maintain a 'to delete list' and continue to retry the delete until it is successful (on another thread with a concurrent collection maybe).
I also don't believe there is anyway to forcefully delete an in-use file.
Upvotes: 1