2010-02-15 3 views
19

J'ai un processus qui sera appelé assez fréquemment à partir de cron pour lire un fichier qui contient certaines commandes liées au déplacement. Mon processus doit lire et écrire dans ce fichier de données - et le garder verrouillé pour empêcher d'autres processus de le toucher pendant ce temps. Un processus complètement séparé peut être exécuté par un utilisateur pour écrire/annexer (potentiellement) à ce même fichier de données. Je veux que ces deux processus jouent bien et n'accèdent au fichier qu'un seul à la fois. Le nl FileLock semblait être ce dont j'avais besoin (à part écrire mes propres fichiers de type sémaphore), mais j'ai du mal à le verrouiller en lecture. Je peux verrouiller et écrire très bien, mais lorsque je tente de créer un verrou en lisant, j'obtiens une exception NonWritableChannelException. Est-il même possible de verrouiller un fichier pour le lire? On dirait qu'un RandomAccessFile est plus proche de ce dont j'ai besoin, mais je ne vois pas comment implémenter cela.Java FileLock pour la lecture et l'écriture

Voici le code qui échoue:

FileInputStream fin = new FileInputStream(f); 
FileLock fl = fin.getChannel().tryLock(); 
if(fl != null) 
{ 
    System.out.println("Locked File"); 
    BufferedReader in = new BufferedReader(new InputStreamReader(fin)); 
    System.out.println(in.readLine()); 
      ... 

L'exception est levée sur la ligne de FileLock.

java.nio.channels.NonWritableChannelException 
at sun.nio.ch.FileChannelImpl.tryLock(Unknown Source) 
at java.nio.channels.FileChannel.tryLock(Unknown Source) 
at Mover.run(Mover.java:74) 
at java.lang.Thread.run(Unknown Source) 

En regardant les JavaDocs, il dit

exception non vérifiée lancée lors d'une tentative d'écriture dans un canal qui n'a pas été ouvert à l'origine pour l'écriture.

Mais je n'ai pas nécessairement besoin d'écrire dessus. Lorsque j'essaie de créer un FileOutpuStream, etc. à des fins d'écriture, il est content jusqu'à ce que j'essaie d'ouvrir un FileInputStream sur le même fichier.

+0

Avez-vous essayé d'utiliser l'appel de la méthode des trois paramètres, Verrouillage FileLock (position longue, taille longue, booléen partagé)? Je n'ai jamais utilisé le FileLock auparavant, je ne publierai donc pas de réponse, mais je pense que l'utilisation de cet appel de méthode peut aider car il semble que vous ayez besoin d'un verrou partagé et non d'un verrou exclusif. a un verrou dessus. – ChadNC

+0

Je pense que l'intention de cela est de verrouiller seulement des parties d'un fichier, mais je voudrais verrouiller le fichier entier pour prévenir et une corruption possible. – bobtheowl2

Répondre

16

(a) Savez-vous que le verrouillage du fichier n'empêche pas les autres processus de le toucher à moins d'utiliser également des verrous?
(b) Vous devez vous verrouiller via un canal inscriptible. Obtenez le verrou via un RandomAccessFile en mode "rw", puis ouvrez votre FileInputStream. Assurez-vous de fermer les deux!

+1

a) oui, j'écrirai les deux processus et je prévois d'implémenter des procédures de verrouillage similaires dans les deux cas. b) Je n'avais pas réalisé que vous pouviez obtenir directement le verrou sur le RandomAccessFile. Pour utiliser le flux File [Input | Output], je devais faire un nouveau FileInputStream (raf.getFD()). Mais, de toute façon en utilisant le flux d'entrée de l'objet RandomAccessFile directement, je peux toujours lire à partir du fichier. Merci – bobtheowl2

+0

Eh? (A) vous ne pouvez pas obtenir un verrou directement à partir de RandomAccessFile, vous devez d'abord obtenir son FileChannel; (B) RandomAccessFile n'a pas de flux d'entrée, mais il met en œuvre DataInput afin que vous puissiez en lire directement. – EJP

10

Ce serait mieux si vous avez créé le verrou en utilisant tryLock(0L, Long.MAX_VALUE, true).

Cela crée un verrou partagé qui est la bonne chose à faire pour la lecture.

tryLock() est un raccourci pour tryLock(0L, Long.MAX_VALUE, false), c'est-à-dire qu'il demande un verrouillage d'écriture exclusif.

+0

Bonne réponse. Ce programme est déjà en ligne, mais cela pourrait certainement être mis à jour dans la prochaine phase.Nous en voyons tellement l'usage maintenant que les verrous exclusifs deviennent encombrants dans certains scénarios. Je vais certainement garder cela à l'esprit pour la prochaine mise à jour. – bobtheowl2

+0

Pourquoi dites-vous qu'un verrou partagé est la bonne chose à faire pour la lecture, cela dépend sûrement de votre cas d'utilisation? Si je veux m'assurer que seulement un processus parmi un certain nombre de processus lit un fichier (par exemple, les agents contrôlant un répertoire de téléchargement pour traiter de nouveaux fichiers), je ne pense pas qu'un verrou partagé soit ce dont j'ai besoin. – codebox

+1

Je l'ai écrit comme ça parce que la lecture n'est pas mutuellement exclusive. Il est en effet possible que plusieurs threads lisent dans un fichier sans interférer alors que l'écriture est toujours exclusive. Gardez à l'esprit que c'était une réponse à la question initiale et ne signifie pas une vérité absolue pour chaque situation. C'est vrai dans 99% des cas d'utilisation, cependant. – Huxi

Questions connexes