Lorsque j'ouvre un fichier, je veux savoir s'il est utilisé par un autre processus afin que je puisse effectuer une manipulation spéciale; toute autre IOException que je vais faire exploser. La propriété Message d'IOException contient "Le processus ne peut pas accéder au fichier 'foo' car il est utilisé par un autre processus.", Mais cela ne convient pas à la détection par programmation. Quelle est la manière la plus sûre et la plus fiable de détecter un fichier utilisé par un autre processus?Comment savoir si une exception IOException interceptée est provoquée par le fichier utilisé par un autre processus, sans recourir à l'analyse de la propriété Message
Répondre
Cette version particulière de IOException
est lancée lorsque le code d'erreur renvoyé par la fonction native Win32 est ERROR_SHARING_VIOLATION
(Documentation). Il a la valeur numérique de 0x20
mais est stockée comme 0x80070020
sur la propriété HRESULT
de l'exception (c'est le résultat d'appeler MakeHRFromErrorCode).
Ainsi, la manière programatic de vérifier une violation de partage est la vérification de la propriété HResult
sur la IOException
pour la valeur 0x80070020
.
public static bool IsSharingViolation(this IOException ex) {
return 0x80070020 == Marshal.GetHRForException(ex);
}
Cependant, je me demande exactement ce que vous voulez faire dans le scénario où il a été lancé à la suite d'une violation de partage. Au moment où l'exception est levée, l'autre processus peut se terminer et donc supprimer la violation.
Pourquoi ne pas utiliser 'ex.HResult 'directement au lieu de' Marshal.GetHRForException'? –
@Anders parce que la propriété HResult a un niveau d'accessibilité de protected donc il n'est généralement pas accessible. – JaredPar
Réponse fantastique JaredPar, merci ... En réponse à votre question; J'ai besoin de détecter ce scénario parce que j'ai besoin d'un message amical pour la couche de présentation - c'est ok si le conflit pourrait ne pas exister le moment suivant, en raison de la nature de mon application ... merci encore –
Je n'ai pas assez « représentant » de commenter si je espère que cette « réponse » est OK ...
La réponse acceptée est exactement ce que je cherchais et fonctionne parfaitement, mais les gens ici et similaires Des questions ont remis en question l'utilité de vérifier si un fichier est verrouillé. Il est correct qu'une fonction d'utilitaire pour tester si un fichier est verrouillé n'est pas très utile car dans l'instruction suivante, le statut aurait pu changer. Mais le modèle consistant à tenter une opération de verrouillage et à répondre différemment aux erreurs de verrouillage par rapport aux erreurs générales est valide et utile. La chose la plus évidente à faire est d'attendre un peu et réessayer l'opération. Ceci peut être généralisé en fonction d'aide comme ceci:
protected static void RetryLock(Action work) {
// Retry LOCK_MAX_RETRIES times if file is locked by another process
for (int i = 1; i <= LOCK_MAX_RETRIES; i++) {
try {
work();
return;
} catch (IOException ex) {
if (i == LOCK_MAX_RETRIES || (uint) ex.HResult != 0x80070020) {
throw;
} else {
// Min should be long enough to generally allow other process to finish
// while max should be short enough such that RETRIES * MAX isn't intolerable
Misc.SleepRandom(LOCK_MIN_SLEEP_MS, LOCK_MAX_SLEEP_MS);
}
}
}
} // RetryLock
... qui peut alors être utilisé comme ceci:
public string DoSomething() {
string strReturn = null;
string strPath = @"C:\Some\File\Path.txt";
// Do some initial work...
//----------------------------------------------------------------------------------------------------
// NESTED FUNCTION to do main logic, RetryLock will retry up to N times on lock failures
Action doWork = delegate {
using (FileStream objFile = File.Open(strPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) {
// Does work here if lock succeeded, else File.Open will throw ex
strReturn = new StreamReader(objFile).ReadLine();
}
}; // delegate doWork
//----------------------------------------------------------------------------------------------------
RetryLock(doWork); // Throws original ex if non-locking related or tried max times
return strReturn;
}
... De toute façon, l'affichage juste au cas où quelqu'un ayant des besoins similaires trouve le motif utile.
Si vous utilisez C# 6 c'est la situation idéale pour utiliser les exceptions filtrées 'catch (IOException ex) quand (i
Le type est-il réellement une exception d'E/S ou est-ce l'un des types dérivés de IOException? –
Par intérêt, pourquoi avez-vous besoin de détecter cela par programme? Que comptez-vous faire une fois que vous avez découvert qu'un autre processus utilise votre fichier? –
@Mark Byers, voir mon commentaire contre la réponse acceptée. –