Quel est le moyen le plus simple de bloquer un thread jusqu'à ce qu'un fichier ait été déverrouillé et soit accessible pour la lecture et le changement de nom? Par exemple, y a-t-il un WaitOnFile () quelque part dans le .NET Framework?
J'ai un service qui utilise un FileSystemWatcher pour rechercher les fichiers à transmettre à un site FTP, mais l' événement créé par le fichier se déclenche avant que l'autre processus n'ait fini d'écrire le fichier.
La solution idéale aurait un délai d'expiration pour que le fil ne se bloque pas indéfiniment avant d'abandonner.
Edit: Après avoir essayé certaines des solutions ci-dessous, j'ai fini par changer le système afin que tous les fichiers soient écrits Path.GetTempFileName()
, puis exécutés File.Move()
à l'emplacement final. Dès que l' FileSystemWatcher
événement s'est déclenché, le fichier était déjà complet.
Réponses:
Voici la réponse que j'ai donnée à une question connexe :
la source
À partir de la réponse d'Eric, j'ai inclus quelques améliorations pour rendre le code beaucoup plus compact et réutilisable. J'espère que c'est utile.
la source
using
sur un null, vérifiez simplement la présence de null à l'intérieur duusing
bloc.fs
être nulle dans lecatch
bloc? Si leFileStream
constructeur lance, la variable ne recevra pas de valeur, et il n'y a rien d'autre à l'intérieur dutry
qui puisse lancer unIOException
. Pour moi, il semble que ce devrait être juste de le fairereturn new FileStream(...)
.Voici un code générique pour ce faire, indépendant de l'opération de fichier elle-même. Voici un exemple d'utilisation:
ou
Vous pouvez également définir le nombre de tentatives et le temps d'attente entre les tentatives.
REMARQUE: Malheureusement, l'erreur Win32 sous-jacente (ERROR_SHARING_VIOLATION) n'est pas exposée avec .NET, j'ai donc ajouté une petite fonction de hack (
IsSharingViolation
) basée sur des mécanismes de réflexion pour vérifier cela.la source
SharingViolationException
. En fait, ils le peuvent encore, de manière rétrocompatible, tant qu'il descend deIOException
. Et ils devraient vraiment, vraiment.Starting with the .NET Framework 4.5, the HResult property's setter is protected, whereas its getter is public. In previous versions of the .NET Framework, both getter and setter are protected.
J'ai organisé une classe d'aide pour ce genre de choses. Cela fonctionnera si vous avez le contrôle sur tout ce qui accède au fichier. Si vous vous attendez à une controverse de la part d'autres choses, cela ne vaut pratiquement rien.
Cela fonctionne en utilisant un mutex nommé. Ceux qui souhaitent accéder au fichier tentent d'acquérir le contrôle du mutex nommé, qui partage le nom du fichier (avec les «\» transformés en «/»). Vous pouvez soit utiliser Open (), qui bloquera jusqu'à ce que le mutex soit accessible, soit vous pouvez utiliser TryOpen (TimeSpan), qui essaie d'acquérir le mutex pour la durée donnée et retourne false s'il ne peut pas acquérir dans le laps de temps. Cela devrait très probablement être utilisé à l'intérieur d'un bloc using, pour garantir que les verrous sont libérés correctement et que le flux (s'il est ouvert) sera correctement éliminé lorsque cet objet sera supprimé.
J'ai fait un test rapide avec ~ 20 choses pour faire diverses lectures / écritures du fichier et je n'ai vu aucune corruption. Évidemment, ce n'est pas très avancé, mais cela devrait fonctionner pour la majorité des cas simples.
la source
Pour cette application particulière, l'observation directe du fichier entraînera inévitablement un bogue difficile à retracer, en particulier lorsque la taille du fichier augmente. Voici deux stratégies différentes qui fonctionneront.
Bonne chance!
la source
L'une des techniques que j'ai utilisées il y a quelque temps était d'écrire ma propre fonction. En gros, interceptez l'exception et réessayez à l'aide d'un minuteur que vous pouvez déclencher pendant une durée spécifiée. S'il y a un meilleur moyen, veuillez partager.
la source
Depuis MSDN :
Votre FileSystemWatcher pourrait être modifié afin qu'il ne fasse pas sa lecture / renommée pendant l'événement "OnCreated", mais plutôt:
la source
Dans la plupart des cas, une approche simple comme @harpo suggérée fonctionnera. Vous pouvez développer un code plus sophistiqué en utilisant cette approche:
la source
Annonce pour transférer le fichier de déclenchement du processus SameNameASTrasferedFile.trg qui est créé une fois la transmission du fichier terminée.
Ensuite, configurez FileSystemWatcher qui déclenchera l'événement uniquement sur le fichier * .trg.
la source
Je ne sais pas ce que vous utilisez pour déterminer l'état de verrouillage du fichier, mais quelque chose comme ça devrait le faire.
la source
Une solution possible serait de combiner un observateur de système de fichiers avec une interrogation,
être notifié pour chaque changement sur un fichier, et lorsque vous recevez une notification, vérifiez s'il est verrouillé comme indiqué dans la réponse actuellement acceptée: https://stackoverflow.com/a/50800/6754146 Le code d'ouverture du flux de fichiers est copié à partir de la réponse et légèrement modifié:
De cette façon, vous pouvez vérifier si un fichier est verrouillé et être averti lorsqu'il est fermé au cours du rappel spécifié, de cette façon, vous évitez l'interrogation trop agressive et ne faites le travail que lorsqu'il est effectivement fermé.
la source
Je le fais de la même manière que Gulzar, continuez d'essayer avec une boucle.
En fait, je ne me soucie même pas de l'observateur du système de fichiers. Interroger un lecteur réseau pour les nouveaux fichiers une fois par minute n'est pas cher.
la source
Utilisez simplement l' événement Changed avec NotifyFilter NotifyFilters.LastWrite :
la source
J'ai rencontré un problème similaire lors de l'ajout d'une pièce jointe Outlook. "Utiliser" a sauvé la journée.
la source
Que diriez-vous de ceci en option:
Bien sûr, si la taille du fichier est préallouée lors de la création, vous obtiendrez un faux positif.
la source