Удаление используемых файлов

Я создал простую программу для удаления временных файлов на С# (для удовольствия, а не для крупного проекта), и я запускаю проблемы с заблокированными файлами (в использовании). Как обычно вы исключаете эти файлы? Для справки я получаю ошибку:

Процесс не может получить доступ к файлу "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;

        } 
    }     

Ответ 1

Описание

Невозможно удалить файл, который в настоящее время используется другим процессом. Но вы можете подождать, пока файл не будет заблокирован.

Завершите цикл 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();

Update

Если вы хотите пропустить заблокированные файлы, вы можете сделать это.

//
var dir = new DirectoryInfo(folderPath);
foreach(var file in dir.GetFiles()) {
    try
    {
        file.Delete();
    }
    catch (IOException)
    {
        //file is currently locked
    }
}

Ответ 2

Ну, я столкнулся с подобными проблемами. Когда вы пытаетесь удалить каталог вскоре после удаления файла, вы должны заставить 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);
        }

    }

Ответ 3

Я не верю, что вы можете заранее знать, используется ли файл или нет. Вы можете попытаться получить исключительную блокировку файла; но тогда вы просто торгуете одним исключением для другого.

Если это файлы, которые вы открываете, посмотрите, не можете ли вы улучшить их закрытие. Если это более сложно, вы можете сохранить "удалить список" и продолжить повторять попытку удаления до тех пор, пока она не будет успешной (возможно, в другом потоке с параллельной коллекцией).

Я также не верю, что в любом случае можно принудительно удалить исполняемый файл.

Ответ 4

В приведенном ниже коде удаляются файлы из каталога и всех его подкаталогов, исключая заблокированные файлы, и получает список файлов, которые не удаляются. Вы можете изменить 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

Существует только один метод, который необходимо вызвать, а именно WipeFile, и код показан ниже. Итак, все, что вам действительно нужно сделать, это вызвать WipeFile и предоставить полный путь к удаляемому файлу, а также количество раз, которое вы хотите перезаписать.

public void WipeFile(string filename, int timesToWrite)
{
    try
    {
        if (File.Exists(filename))
        {
            // Set the files attributes to normal in case it 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

Ответ 6

Попробуйте использовать следующий код. Просто добавьте две строки перед удалением файла:

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