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;
}
}
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;
}
FileInfo file = new FileInfo("PathToTheFile");
while (IsFileLocked(file))
Thread.Sleep(1000);
file.Delete();
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
}
}
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);
}
}
Essayez le code suivant. Ajoutez simplement deux lignes avant la suppression du fichier:
GC.Collect();
GC.WaitForPendingFinalizers();
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);
}
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.
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);
}
}
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.