2010-06-23 6 views

Répondre

9

Utilisez un javax.swing.ProgressMonitorInputStream.

+0

Je pense que ce sera assez proche. Merci! – Danijel

+0

Pourriez-vous répondre plus simplement? :) – Matthieu

1

En supposant que vous sachiez combien d'articles vous avez, ne pouvez-vous pas garder un compteur dans le gestionnaire? Par exemple.

public void startElement (String uri, String localName, 
          String qName, Attributes attributes) 
          throws SAXException { 
    if(qName.equals("article")){ 
     counter++ 
    } 
    ... 
} 

(Je ne sais pas si vous analysez « article », il est juste un exemple)

Si vous ne connaissez pas le numéro de l'article à l'avance, vous aurez besoin de compter d'abord . Ensuite, vous pouvez imprimer le statut nb tags read/total nb of tags, disons chaque 100 étiquettes (counter % 100 == 0).

Ou même d'avoir un autre thread surveiller la progression. Dans ce cas, vous pouvez vouloir synchroniser l'accès au compteur, mais ce n'est pas nécessaire étant donné qu'il n'a pas besoin d'être vraiment précis.

Mes 2 cents

+0

Je l'ai compris, mais je cherchais un moyen de le faire sans avoir besoin de compter les articles en premier. Je pensais que peut-être il y avait un moyen de trouver la position de l'analyseur dans le fichier à la place, parce que je peux facilement obtenir la taille du fichier. – Danijel

2

Vous pouvez obtenir une estimation de la ligne courante/colonne dans votre fichier en remplaçant la méthode setDocumentLocator de org.xml.sax.helpers.DefaultHandler/BaseHandler. Cette méthode est appelée avec un objet à partir duquel vous pouvez obtenir une approximation de la ligne/colonne actuelle si nécessaire.

Editer: Au meilleur de ma connaissance, il n'y a pas de moyen standard pour obtenir la position absolue. Cependant, je suis sûr que certaines implémentations SAX offrent ce genre d'informations.

+0

Fermez, mais alors je devrais connaître le nombre de lignes dans le fichier, non? – Danijel

+0

En effet. Une autre idée aurait pu être soulignée par l'énigmatique EJP. Vous pouvez estimer la progression en utilisant l'avancement dans le flux d'entrée. Cependant, ce n'est pas non plus la progression de l'analyse, en raison de la mise en mémoire tampon potentielle et des retards. –

0

j'utiliser la position de flux d'entrée. Créez votre propre classe de flux triviale qui délègue/hérite du "vrai" et garde la trace des octets lus. Comme vous le dites, obtenir la taille totale du fichier est facile. Je ne m'inquiéterais pas de la mise en mémoire tampon, de la prévisualisation, etc. - pour les gros fichiers comme ceux-ci, c'est de la volaille. D'un autre côté, je limiterais la position à "99%".

10

Merci à la suggestion de EJP de ProgressMonitorInputStream, à la fin j'ai étendu FilterInputStream de sorte que ChangeListener peut être utilisé pour surveiller l'emplacement de lecture en cours en termes d'octets. Avec ceci vous avez un contrôle plus fin, par exemple pour montrer plusieurs barres de progression pour la lecture parallèle de gros fichiers XML. Ce qui est exactement ce que j'ai fait.

Ainsi, une version simplifiée du flux monitorable:

/** 
* A class that monitors the read progress of an input stream. 
* 
* @author Hermia Yeung "Sheepy" 
* @since 2012-04-05 18:42 
*/ 
public class MonitoredInputStream extends FilterInputStream { 
    private volatile long mark = 0; 
    private volatile long lastTriggeredLocation = 0; 
    private volatile long location = 0; 
    private final int threshold; 
    private final List<ChangeListener> listeners = new ArrayList<>(4); 


    /** 
    * Creates a MonitoredInputStream over an underlying input stream. 
    * @param in Underlying input stream, should be non-null because of no public setter 
    * @param threshold Min. position change (in byte) to trigger change event. 
    */ 
    public MonitoredInputStream(InputStream in, int threshold) { 
     super(in); 
     this.threshold = threshold; 
    } 

    /** 
    * Creates a MonitoredInputStream over an underlying input stream. 
    * Default threshold is 16KB, small threshold may impact performance impact on larger streams. 
    * @param in Underlying input stream, should be non-null because of no public setter 
    */ 
    public MonitoredInputStream(InputStream in) { 
     super(in); 
     this.threshold = 1024*16; 
    } 

    public void addChangeListener(ChangeListener l) { if (!listeners.contains(l)) listeners.add(l); } 
    public void removeChangeListener(ChangeListener l) { listeners.remove(l); } 
    public long getProgress() { return location; } 

    protected void triggerChanged(final long location) { 
     if (threshold > 0 && Math.abs(location-lastTriggeredLocation) < threshold) return; 
     lastTriggeredLocation = location; 
     if (listeners.size() <= 0) return; 
     try { 
     final ChangeEvent evt = new ChangeEvent(this); 
     for (ChangeListener l : listeners) l.stateChanged(evt); 
     } catch (ConcurrentModificationException e) { 
     triggerChanged(location); // List changed? Let's re-try. 
     } 
    } 


    @Override public int read() throws IOException { 
     final int i = super.read(); 
     if (i != -1) triggerChanged(location++); 
     return i; 
    } 

    @Override public int read(byte[] b, int off, int len) throws IOException { 
     final int i = super.read(b, off, len); 
     if (i > 0) triggerChanged(location += i); 
     return i; 
    } 

    @Override public long skip(long n) throws IOException { 
     final long i = super.skip(n); 
     if (i > 0) triggerChanged(location += i); 
     return i; 
    } 

    @Override public void mark(int readlimit) { 
     super.mark(readlimit); 
     mark = location; 
    } 

    @Override public void reset() throws IOException { 
     super.reset(); 
     if (location != mark) triggerChanged(location = mark); 
    } 
} 

Il ne sait pas - ou de soins - la taille du flux sous-jacent est, vous devez donc obtenir d'une autre manière, par exemple de le fichier lui-même.

Alors, va ici l'utilisation de l'échantillon simplifié:

try (
    MonitoredInputStream mis = new MonitoredInputStream(new FileInputStream(file), 65536*4) 
) { 

    // Setup max progress and listener to monitor read progress 
    progressBar.setMaxProgress((int) file.length()); // Swing thread or before display please 
    mis.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { 
     SwingUtilities.invokeLater(new Runnable() { @Override public void run() { 
     progressBar.setProgress((int) mis.getProgress()); // Promise me you WILL use MVC instead of this anonymous class mess! 
     }}); 
    }}); 
    // Start parsing. Listener would call Swing event thread to do the update. 
    SAXParserFactory.newInstance().newSAXParser().parse(mis, this); 

} catch (IOException | ParserConfigurationException | SAXException e) { 

    e.printStackTrace(); 

} finally { 

    progressBar.setVisible(false); // Again please call this in swing event thread 

} 

Dans mon cas, les progrès soulèvent bien de gauche à droite sans sauts anormaux. Ajuster le seuil pour un équilibre optimal entre performance et réactivité. Trop petit et la vitesse de lecture peut plus que doubler sur de petits appareils, trop gros et les progrès ne seraient pas faciles.

Espérons que ça aide. N'hésitez pas à modifier si vous avez trouvé des erreurs ou des fautes de frappe, ou votez pour m'envoyer quelques encouragements!: D

+0

Excellent! Exactement ce que je cherchais, je vais l'adapter, merci! :) – Matthieu

Questions connexes