2016-03-24 1 views
2

Il y a quelques questions de Java semblables à celui-ci mais aucun d'entre eux n'avait accepté des réponses que je pourrais trouver et ma situation est un peu plus spécifique. J'ai un programme qui traite les fichiers un par un lorsqu'ils sont introduits dans un répertoire. Parfois, les fichiers peuvent rester verrouillés en cours d'utilisation par le programme les déposant pendant quelques secondes après qu'ils soient visibles à mon programme. Je n'ai aucun contrôle sur ce programme. Dans mon programme j'ai déjà la gestion des erreurs à récupérer si un fichier est utilisé lorsque mon programme essaie de le lire. Il en résulte que le fichier est entièrement ignoré. Ce que je veux implémenter est un schéma de réessai pour voir si le fichier est déverrouillé après quelques secondes. Dans une autre question ici, j'ai trouvé une suggestion pour utiliser FileUtils.touch(). C'est pratique car j'utilise déjà FileUtils dans mon projet. Selon le javadoc, FileUtils.touch() avec jeter un IOException si le fichier est utilisé par un autre processus. Super. Cependant, l'un des commentaires de la réponse que j'ai mentionnée mettait en garde contre une condition de concurrence sans aucune explication. Voici le code que je considère la mise en œuvre:En attente de la libération de fichiers

// Implementing Sason's suggestion 
int retries = 0; 
while (retries < MAX_RETRIES) { 
    try { 
     processFile(file); 
    } catch (IOException ioe) { 
     // Assumes this is a file in use exception... bad thing? 
     log.warn("File is in use. Waiting 1 second to retry."); 
     retries++; 
     try { 
      Thread.sleep(1000); 
     } catch (InterruptedException ie) { 
      log.warn("Thread interrupted while waiting for file lock to clear."); 
      break; 
     } 
    } 
} 

Je me rends compte que le fichier pourrait devenir à nouveau verrouillés entre le FileUtils.touch() et l'appel de méthode processFile() (et je suppose que c'est la condition de course mis en garde contre en la réponse non acceptée j'ai trouvé) mais c'est bien. La méthode processFile() gère simplement l'erreur de verrouillage comme c'est le cas actuellement. Pour être clair, dans ce cas, il est parfaitement possible que le fichier soit ouvert par un autre processus, mais il ne peut pas être verrouillé.

En outre, alors que parfois le fichier est déverrouillé après une seconde ou deux, dans certains cas, le programme supprimant les fichiers conserve le verrou indéfiniment. J'ai également besoin d'éviter infiniment d'essayer de retraiter le même fichier ainsi que d'être capable d'informer l'expéditeur lorsqu'un fichier ne peut pas être traité après que les tentatives aient été épuisées.

Alors, est-ce qu'il me manque quelque chose ici? Y a-t-il un moyen meilleur/plus sûr de le faire?

+0

Il ne semble pas que 'touch()' soit un moyen fiable de tester si le fichier est ouvert. Il peut fonctionner sur un système particulier avec un processus particulier d'écriture du fichier, et c'est bien, mais si vous exécutez le code ailleurs ou si vous changez d'éditeur, vous devrez effectuer un nouveau test pour vous assurer qu'il fonctionne toujours. La bonne façon de le faire est avec un 'FileLock', mais cela nécessite que le programme d'écriture utilise le mécanisme de verrouillage du système de fichiers sous-jacent. – erickson

+0

J'aurais dû être plus clair dans ma question. C'est correct si le fichier est ouvert dans un autre processus qui n'a pas le fichier verrouillé (comme, par exemple, NotePad ++). Il ne peut simplement pas être verrouillé car 'processFile()' tentera de verrouiller le fichier. Je vois ce que vous pensez de 'FileLock', mais vous avez raison: cela nécessiterait beaucoup de refactoring. Je pense que 'touch()' fonctionnera sur plusieurs plates-formes avec la même mise en garde qu'un autre programme pourrait avoir le fichier ouvert mais pas verrouillé. –

Répondre

3

Je voudrais utiliser un SchedueledExecutorService pour soumettre le travail avec un certain délai qui essaie de traiter le fichier. Si le traitement échoue, publiez le travail encore et encore jusqu'à ce qu'il réussisse.

Est-ce que FileUtils.touch est nécessaire ici? Pourquoi ne pas simplement essayer de lire le fichier et s'il échoue réessayer?

La chose thread.sleep est plutôt moche. Si vous traitez plusieurs fichiers, chacun doit utiliser son propre thread jusqu'à ce que cela soit fait. Un ScheduleredExecutorService serait plus efficace.

+0

Je suis d'accord. La course est parce qu'il n'y a pas d'atomicité entre le chèque et l'action. Si l'action échoue parce qu'elle ne peut pas acquérir de verrou, aucun problème. Essayez juste plus tard. – erickson

+0

C'est une idée intéressante que j'avais envisagée et rejetée initialement parce que parfois le fichier resterait verrouillé indéfiniment et le programme serait bloqué en boucle sur un fichier qui ne peut pas être traité. Dans la gestion des erreurs, une notification est fournie à l'expéditeur indiquant que le fichier ne peut pas être traité et que le fichier est ajouté à une liste d'ignorés.À la fin de la journée, une liste de fichiers qui n'ont pas pu être traités est envoyée à l'expéditeur. Je ne veux pas vraiment changer ce comportement Je veux juste laisser quelques secondes pour que le fichier soit disponible avant de finir sur la liste non traitée. –

+0

Aussi, je suis d'accord que la chose Thread.sleep() est un peu moche, mais les fichiers doivent être gérés de manière synchrone de toute façon, donc c'est OK si cela bloque le prochain fichier à traiter. Je souhaite presque que je n'ai pas eu à traiter les fichiers séquentiellement (aussi près que possible de l'ordre d'arrivée). Cela simplifierait un peu les choses parce que je pourrais faire exactement ce que vous avez dit et faire expirer le runnable après un certain nombre de tentatives. Je pourrais même utiliser Future à la place. –