C# 删除正在使用的文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10504647/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Deleting files in use
提问by Geekender
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:
我创建了一个简单的程序来删除 C# 中的临时文件(为了好玩,不是一个主要项目)并且遇到了锁定文件(正在使用)的问题。你通常如何排除这些文件?作为参考,我收到错误:
The process cannot access the file 'ExchangePerflog_8484fa31c65c7a31cfcccd43.dat' because it is being used by another process.
该进程无法访问文件“ExchangePerflog_8484fa31c65c7a31cfcccd43.dat”,因为它正被另一个进程使用。
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;
}
}
回答by Rob P.
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.
我也不相信有任何方法可以强行删除正在使用的文件。
回答by dknaack
Description
描述
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
签入while循环,直到使用此方法解锁文件
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;
}
Sample
样本
FileInfo file = new FileInfo("PathToTheFile");
while (IsFileLocked(file))
Thread.Sleep(1000);
file.Delete();
Update
更新
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
}
}
回答by Aravindhkumar
Try the following code. Just add two lines before file deletion:
试试下面的代码。只需在文件删除前添加两行:
GC.Collect();
GC.WaitForPendingFinalizers();
回答by Chris
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.
下面的代码将从目录及其所有子目录中删除文件,不包括锁定的文件,并获取未删除的文件列表。如果仅考虑当前目录,则可以将 SearchOption 更改为 TopDirectoryOnly。
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);
}
}
回答by Bartosz Gawron
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
好吧,我遇到了类似的问题。当您在删除文件后不久尝试删除目录时,您必须强制 GC 从当前线程释放文件句柄
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);
}
}
回答by Taras Kovalenko
There is only one method that you need to call, namely WipeFile and the code is as shown below. So, all you really have to do is call WipeFile and supply the full path of the file to be deleted, as well as the number of times you want to overwrite it.
您只需要调用一种方法,即WipeFile,代码如下所示。因此,您真正需要做的就是调用 WipeFile 并提供要删除的文件的完整路径,以及您想要覆盖它的次数。
public void WipeFile(string filename, int timesToWrite)
{
try
{
if (File.Exists(filename))
{
// Set the files attributes to normal in case it's read-only.
File.SetAttributes(filename, FileAttributes.Normal);
// Calculate the total number of sectors in the file.
double sectors = Math.Ceiling(new FileInfo(filename).Length/512.0);
// Create a dummy-buffer the size of a sector.
byte[] dummyBuffer = new byte[512];
// Create a cryptographic Random Number Generator.
// This is what I use to create the garbage data.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
// Open a FileStream to the file.
FileStream inputStream = new FileStream(filename, FileMode.Open);
for (int currentPass = 0; currentPass < timesToWrite; currentPass++)
{
UpdatePassInfo(currentPass + 1, timesToWrite);
// Go to the beginning of the stream
inputStream.Position = 0;
// Loop all sectors
for (int sectorsWritten = 0; sectorsWritten < sectors; sectorsWritten++)
{
UpdateSectorInfo(sectorsWritten + 1, (int) sectors);
// Fill the dummy-buffer with random data
rng.GetBytes(dummyBuffer);
// Write it to the stream
inputStream.Write(dummyBuffer, 0, dummyBuffer.Length);
}
}
// Truncate the file to 0 bytes.
// This will hide the original file-length if you try to recover the file.
inputStream.SetLength(0);
// Close the stream.
inputStream.Close();
// As an extra precaution I change the dates of the file so the
// original dates are hidden if you try to recover the file.
DateTime dt = new DateTime(2037, 1, 1, 0, 0, 0);
File.SetCreationTime(filename, dt);
File.SetLastAccessTime(filename, dt);
File.SetLastWriteTime(filename, dt);
// Finally, delete the file
File.Delete(filename);
WipeDone();
}
}
catch(Exception e)
{
WipeError(e);
}
}
I have added some events just to be able to keep track of what's happening during the process.
我添加了一些事件只是为了能够跟踪过程中发生的事情。
- PassInfoEvent - Returns which pass is running and the total number of passes to be run.
- SectorInfoEvent - Returns which sector is being written to and the total number of sectors to be written to.
- WipeDoneEvent - An indicator that the wipe process is done.
- WipeErrorEvent - Returns the exception if anything went wrong.
- PassInfoEvent - 返回正在运行的通行证以及要运行的通行证总数。
- SectorInfoEvent - 返回正在写入的扇区和要写入的扇区总数。
- WipeDoneEvent - 擦除过程已完成的指示器。
- WipeErrorEvent - 如果出现任何错误,则返回异常。
回答by Martin
Using dknaack's code. This worked in my case.
使用 dknaack 的代码。这在我的情况下有效。
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);
}

