2010-06-23 7 views

Antwort

9

Verwenden Sie ein javax.swing.ProgressMonitorInputStream.

+0

Ich denke, das wird nah genug sein. Vielen Dank! – Danijel

+0

Kann eine Antwort einfacher sein ?! :) – Matthieu

1

Angenommen, Sie wissen, wie viele Artikel Sie haben, können Sie nicht einfach einen Zähler im Handler behalten? Z.B.

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

(ich weiß nicht, ob Sie „Artikel“ parsen, es ist nur ein Beispiel)

Wenn Sie die Anzahl der Artikel im Voraus nicht wissen, müssen Sie es zuerst zählen . Dann können Sie den Status nb tags read/total nb of tags drucken, sagen Sie jeweils 100 Tags (counter % 100 == 0).

Oder sogar einen anderen Thread überwachen den Fortschritt. In diesem Fall möchten Sie möglicherweise den Zugriff auf den Zähler synchronisieren, dies ist jedoch nicht erforderlich, da er nicht wirklich genau sein muss.

Meine 2 Cent

+0

Ich fand das heraus, aber ich suchte nach einer Möglichkeit, es zu tun, ohne zuerst die Artikel zählen zu müssen. Ich dachte, dass es vielleicht eine Möglichkeit gäbe, die Position des Parsers in der Datei herauszufinden, weil ich die Dateigröße leicht erreichen kann. – Danijel

2

Sie können durch Überschreiben der Methode setDocumentLocator von org.xml.sax.helpers.DefaultHandler/BaseHandler eine Schätzung der aktuellen Zeile/Spalte in der Datei. Diese Methode wird mit einem Objekt aufgerufen, von dem Sie bei Bedarf eine Approximation der aktuellen Zeile/Spalte erhalten können.

Bearbeiten: Nach meinem Wissen gibt es keinen Standard Weg, um die absolute Position zu erhalten. Ich bin mir jedoch sicher, dass einige SAX-Implementierungen diese Art von Informationen anbieten.

+0

Schließen, aber dann müsste ich die Anzahl der Zeilen in der Datei wissen, oder? – Danijel

+0

In der Tat. Eine andere Idee könnte durch die rätselhafte EJP aufgezeigt worden sein. Sie können den Fortschritt schätzen, indem Sie den Fortschritt im Eingabestream verwenden. Dies ist jedoch nicht der Fortschritt in der Analyse, wegen möglicher Pufferung und Lookaheads. –

0

ich den Eingangsstrom Position verwenden würde. Machen Sie Ihre eigene triviale Stream-Klasse, die delegiert/erbt von der "echten" Klasse und verfolgt die gelesenen Bytes. Wie Sie sagen, ist es einfach, die gesamte Dateigröße zu erhalten. Ich mache mir keine Gedanken über Pufferung, Lookahead usw. - für große Dateien wie diese ist es Chickenfeed. Auf der anderen Seite würde ich die Position auf "99%" beschränken.

10

Dank EJPs Vorschlag von ProgressMonitorInputStream habe ich am Ende FilterInputStream erweitert, so dass ChangeListener verwendet werden kann, um den aktuellen Leseort in Bytes zu überwachen.

Damit haben Sie feinere Kontrolle, zum Beispiel mehrere Fortschrittsbalken für das parallele Lesen von großen XML-Dateien anzuzeigen. Was genau ich getan habe.

So ist eine vereinfachte Version des überwachbar stream:

/** 
* 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); 
    } 
} 

Er weiß nicht, - oder Pflege - wie groß der zugrunde liegenden Stream ist, so müssen Sie es auf eine andere Weise zu bekommen, wie aus die Datei selbst

So, hier geht die vereinfachte Proben Nutzung:

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 

} 

In meinem Fall die Fortschritte schön nach rechts, ohne anormalen Sprünge von links heben. Stellen Sie den Schwellenwert für ein optimales Verhältnis zwischen Leistung und Reaktionszeit ein. Zu klein und die Lesegeschwindigkeit kann sich bei kleinen Geräten mehr als verdoppeln, zu groß und der Fortschritt wäre nicht glatt.

Ich hoffe, es hilft. Fühlen Sie sich frei zu bearbeiten, wenn Sie Fehler oder Tippfehler gefunden haben, oder stimmen Sie ab, um mir einige Ermutigungen zu senden!: D

+0

Ausgezeichnet! Genau das, was ich gesucht habe, werde ich anpassen, danke! :) – Matthieu