删除正在使用的文件

时间:2012-05-08 18:51:25

标签: c#

我创建了一个简单的程序来删除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;

        } 
    }     

7 个答案:

答案 0 :(得分:15)

描述

无法删除其他进程当前正在使用的文件。但是你可以等到文件没有被锁定。

检查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
    }
}

答案 1 :(得分:4)

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

    }

答案 2 :(得分: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);
}

答案 3 :(得分:0)

我不相信如果文件正在使用中,您可以提前知道。您可以尝试获取文件的独占锁定;但那时你只是为另一个交易一个例外。

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

我也不相信强行删除正在使用的文件。

答案 4 :(得分: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);    
    }
}

答案 5 :(得分: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 - 如果出现任何错误,则返回异常。

Securely Delete a File using .NET

答案 6 :(得分:-1)

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

GC.Collect();
GC.WaitForPendingFinalizers();