web-dev-qa-db-fra.com

Suppression de fichiers en cours d'utilisation

J'ai créé un programme simple pour supprimer les fichiers temporaires en C # (pour le plaisir, pas un projet majeur) et je rencontre des problèmes de fichiers verrouillés (en cours d'utilisation). Comment excluez-vous normalement ces fichiers? Pour référence, je reçois l'erreur:

Le processus ne peut pas accéder au fichier "ExchangePerflog_8484fa31c65c7a31cfcccd43.dat" car il est utilisé par un autre processus.

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;

        } 
    }     
19
Geekender

La description

Il n'existe aucun moyen de supprimer un fichier actuellement utilisé par un autre processus. Mais vous pouvez attendre que le fichier ne soit pas verrouillé.

Archiver une boucle while jusqu'à ce que le fichier soit déverrouillé avec cette méthode

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

Échantillon

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

Mettre à jour

Si vous souhaitez ignorer les fichiers verrouillés, vous pouvez le faire.

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

Eh bien, j'ai rencontré des problèmes similaires. Lorsque vous essayez de supprimer le répertoire peu de temps après la suppression du fichier, vous devez forcer GC à libérer le descripteur de fichier du thread actuel

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);
        }

    }
4
Bartosz Gawron

Essayez le code suivant. Ajoutez simplement deux lignes avant la suppression du fichier:

GC.Collect();
GC.WaitForPendingFinalizers();
1
Aravindhkumar

Utilisation du code de dknaack. Cela a fonctionné dans mon cas.

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);
}
1
Martin

Je ne pense pas que vous puissiez savoir à l'avance si le fichier est en cours d'utilisation ou non. Vous pouvez essayer d'obtenir un verrou exclusif sur le fichier; mais vous échangeriez simplement une exception contre une autre.

S'il s'agit de fichiers que vous ouvrez, voyez si vous ne pouvez pas mieux les fermer. Si c'est plus compliqué que cela - vous pouvez conserver une liste de suppression et continuer de réessayer la suppression jusqu'à ce qu'elle réussisse (sur un autre thread avec une collection simultanée peut-être).

Je ne pense pas non plus qu'il existe de toute façon de supprimer de force un fichier en cours d'utilisation.

0
Rob P.

Le code ci-dessous supprimera les fichiers d'un répertoire et de tous ses sous-répertoires à l'exception des fichiers verrouillés et obtient la liste des fichiers qui ne sont pas supprimés. Vous pouvez remplacer SearchOption par TopDirectoryOnly si vous ne considérez que le répertoire actuel.

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);    
    }
}
0
Chris

Il n'y a qu'une seule méthode que vous devez appeler, à savoir WipeFile et le code est comme indiqué ci-dessous. Donc, tout ce que vous avez à faire est d'appeler WipeFile et de fournir le chemin complet du fichier à supprimer, ainsi que le nombre de fois que vous souhaitez le remplacer.

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);
    }
}

J'ai ajouté quelques événements juste pour pouvoir suivre ce qui se passe pendant le processus.

  • PassInfoEvent - Retourne quelle passe est en cours d'exécution et le nombre total de passes à exécuter.
  • SectorInfoEvent - Renvoie le secteur dans lequel écrire et le nombre total de secteurs dans lesquels écrire.
  • WipeDoneEvent - Un indicateur que le processus de nettoyage est terminé.
  • WipeErrorEvent - Renvoie l'exception en cas de problème.

Supprimer un fichier en toute sécurité à l'aide de .NET

0
Taras Kovalenko