2010-10-27 4 views
0

Java IO implementation of unix/linux "tail -f" a un problème similaire; mais la solution n'est pas viable pour les fichiers journaux qui génèrent environ 50-100 lignes par seconde.Java - RandomAccessFile (Émulation de la fonction queue de Linux)

J'ai un algorithme qui émule la fonctionnalité queue dans Linux. Par exemple,

File _logFile = new File("/tmp/myFile.txt"); 
long _filePtr = _logFile.length(); 

while (true) 
{ 
    long length = _logFile.length(); 
    if (length < _filePtr) 
    { 
      // means file was truncated 
    } 
    else if (length > _filePtr) 
    { 
      // means something was added to the file 
    } 
// we ignore len = _filePtr ... nothing was written to file 
} 

Mon problème est quand: « quelque chose a été ajouté au fichier » (se référant à la déclaration else if()).

else if (length > _filePtr) 
{ 
    RandomAccessFile _raf = new RandomAccessFile(_logFile, "r"); 
    raf.seek(_filePtr); 

    while ((curLine = raf.readLine()) != null) 
      myTextPane.append(curLine); 

     _filePtr = raf.getFilePointer(); 
     raf.close(); 
} 

Les blocs de programme à tout ((CurLine = raf.readLine()) .... après 15 secondes de l'exécution (Note:. Que le programme fonctionne bien pour les 15 premières secondes)

Il semble que raf.readLine() est jamais frapper NULL, parce que je crois que ce fichier journal est écrit si vite que nous entrons dans un « chat sans fin et de la souris » boucle.

Quelle est la meilleure façon d'imiter La queue de Linux?

Répondre

2

Je pense que vous seriez mieux servi en saisissant un bloc de b ytes en fonction de la longueur du fichier, puis relâchez le fichier et analysez un ByteArrayInputStream (au lieu d'essayer de lire directement à partir du fichier).

Utilisez donc RandomAccessFile # read (octet []) et dimensionnez le tampon en utilisant la longueur du fichier renvoyé. Vous n'aurez pas toujours la fin exacte du fichier, mais c'est normal avec ce type d'algorithme d'interrogation. En passant, cet algorithme est horrible - vous exécutez des opérations d'E/S dans une boucle serrée folle - les appels à Fichier # longueur() vont bloquer, mais pas beaucoup. Attendez-vous à cette routine pour prendre votre application à genoux CPU-sage. Je n'ai pas forcément une meilleure solution pour vous (enfin - en fait, je l'ai - l'application source écrit dans un flux au lieu d'un fichier - mais je reconnais que ce n'est pas toujours faisable). En plus de ce qui précède, vous pouvez introduire un délai d'interrogation (dormez le fil de 100ms chaque boucle - il me semble que vous affichez une interface graphique - un délai de 100ms ne fera de mal à personne, et grandement améliorer la performance des opérations de swing). Ok - bœuf final: Vous ajustez un composant Swing à partir de ce que (j'espère) le code ne fonctionne pas sur l'EDT. Utilisez SwingWorker # invokeLater() pour mettre à jour votre volet de texte.

+0

Merci Kevin! Pouvez-vous clarifier ce que "EDT" signifie sur votre dernier paragraphe? –

+2

Thread Event Dispatch - un rapide google sur cette phrase vous donnera ce que vous devez savoir. Long et court: il est invalide de faire des changements d'état aux composants Swing sauf si vous le faites depuis l'EDT. –

0

Il semble que j'ai trouvé le problème et créé une solution.

Sous l'instruction else if:

while ((curLine = raf.readLine()) != null) 
    myTextPane.append(curLine); 

Ce fut le problème. la méthode append (String) de myTextPane (qui est une classe dérivée de JTextPane) a évoqué "setCaretPosition()" à chaque ajout de ligne qui EST BAD !! Cela signifie que setCaretPosition() a été appelé 50-100 Hz en essayant de "faire défiler vers le bas". Cela a provoqué un blocage de l'interface.

Une solution simple consistait à créer une classe StringBuffer et à ajouter "curLine" jusqu'à ce que raf.readLine() soit vide. Ensuite, ajoutez le StringBuffer et voila ... plus de blocage de setCaretPosition()!

Merci à Kevin de m'avoir amené vers la bonne direction.

0

Vous pouvez toujours exec le programme de la queue:

BufferedReader in = new BufferedReader(new InputStreamReader(
      Runtime.getRuntime().exec("tail -F /tmp/myFile.txt").getInputStream())); 
    String line; 
    while ((line = in.readLine()) != null) { 
     // process line 
    } 
+0

Malheureusement, cette approche fonctionne rarement. – chrisapotek