24

我创建了一个简单的程序来删除 C# 中的临时文件(为了好玩,不是主要项目)并且遇到了锁定文件(使用中)的问题。您通常如何排除这些文件?作为参考,我收到错误:

该进程无法访问文件“ExchangePerflog_8484fa31c65c7a31cfcccd43.dat”,因为它正被另一个进程使用。

代码:

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;

        } 
    }     
4

7 回答 7

21

描述

无法删除另一个进程当前正在使用的文件。但是您可以等到文件未锁定。

签入 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;
}

样本

FileInfo file = new FileInfo("PathToTheFile");
while (IsFileLocked(file))
    Thread.Sleep(1000);
file.Delete();

更新

如果你想跳过锁定的文件,你可以这样做。

//
var dir = new DirectoryInfo(folderPath);
foreach(var file in dir.GetFiles()) {
    try
    {
        file.Delete();
    }
    catch (IOException)
    {
        //file is currently locked
    }
}
于 2012-05-08T18:58:53.427 回答
7

试试下面的代码。只需在文件删除前添加两行:

GC.Collect();
GC.WaitForPendingFinalizers();
于 2016-02-04T08:01:09.637 回答
7

好吧,我遇到了类似的问题。当您在删除文件后不久尝试删除目录时,您必须强制 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);
        }

    }
于 2016-09-27T14:17:41.607 回答
1

我不相信有任何方法可以提前知道文件是否正在使用。您可以尝试获取文件的排他锁;但是你只会用一个例外换另一个例外。

如果这些是您正在打开的文件,请查看是否无法更好地关闭它们。如果它比这更复杂 - 您可以维护一个“删除列表”并继续重试删除,直到它成功(可能在另一个具有并发集合的线程上)。

我也不相信无论如何都可以强制删除正在使用的文件。

于 2012-05-08T18:57:43.977 回答
1

使用 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);
}
于 2018-11-15T00:53:18.740 回答
0

以下代码将从目录及其所有子目录中删除文件,不包括锁定文件,并获取未删除文件的列表。如果只考虑当前目录,则可以将 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);    
    }
}
于 2016-02-04T08:43:12.203 回答
0

您只需调用一个方法,即 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);
    }
}

我添加了一些事件只是为了能够跟踪过程中发生的事情。

  • PassInfoEvent - 返回正在运行的通道以及要运行的通道总数。
  • SectorInfoEvent - 返回正在写入的扇区以及要写入的扇区总数。
  • WipeDoneEvent - 擦除过程完成的指示器。
  • WipeErrorEvent - 如果出现任何问题,则返回异常。

使用 .NET 安全删除文件

于 2016-09-27T14:21:09.430 回答