2010-06-23 14 views

Respuesta

9

Utilice un javax.swing.ProgressMonitorInputStream.

+0

Creo que esto será lo suficientemente cerca. ¡Gracias! – Danijel

+0

¿Podría una respuesta ser más simple que eso? :) – Matthieu

1

Suponiendo que sepa cuántos artículos tiene, ¿no puede mantener un contador en el controlador? P.ej.

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

(no sé si se está analizando "artículo", es sólo un ejemplo)

Si no conoce el número del artículo de antemano, tendrá que contar primero . Luego puede imprimir el estado nb tags read/total nb of tags, digamos cada 100 etiquetas (counter % 100 == 0).

O incluso tenga otro subproceso que controle el progreso. En este caso, es posible que desee sincronizar el acceso al contador, pero no es necesario ya que no necesita ser realmente preciso.

Mis 2 centavos

+0

Me di cuenta de eso, pero estaba buscando una forma de hacerlo sin tener que contar primero los artículos. Pensé que tal vez había una forma de averiguar la posición del analizador en el archivo, porque puedo obtener fácilmente el tamaño del archivo. – Danijel

2

Usted puede obtener una estimación de la línea/columna actual en el archivo reemplazando el método de setDocumentLocatororg.xml.sax.helpers.DefaultHandler/BaseHandler. Se llama a este método con un objeto desde el que puede obtener una aproximación de la línea/columna actual cuando sea necesario.

Editar: Por lo que yo sé, no hay una forma estándar de obtener la posición absoluta. Sin embargo, estoy seguro de que algunas implementaciones de SAX ofrecen este tipo de información.

+0

Cerrar, pero entonces tendría que saber el número de líneas en el archivo, ¿verdad? – Danijel

+0

De hecho. Otra idea podría haber sido señalada por el enigmático EJP. Puede estimar el progreso, utilizando el avance en la secuencia de entrada. Sin embargo, este no es el progreso en el análisis sintáctico, debido a la posibilidad de almacenamiento en memoria intermedia y lookaheads. –

0

que haría uso de la posición de flujo de entrada. Cree su propia clase de flujo trivial que delegue/herede de la "real" y realice un seguimiento de los bytes leídos. Como dices, obtener el tamaño total del archivo es fácil. No me preocuparía el almacenamiento en búfer, la búsqueda anticipada, etc., para archivos grandes como estos es el de alimentación de pollo. Por otro lado, limitaría la posición a "99%".

10

Gracias a la sugerencia de EJP de ProgressMonitorInputStream, al final extendí FilterInputStream para que ChangeListener se pueda utilizar para supervisar la ubicación de lectura actual en términos de bytes.

Con esto tiene un control más fino, por ejemplo, para mostrar barras de progreso múltiples para lectura paralela de archivos xml grandes. Que es exactamente lo que hice.

Por lo tanto, una versión simplificada de la corriente controlable:

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

no sabe - o cuidado - lo grande que la corriente subyacente es, por lo que necesita para obtener de alguna otra forma, como por ejemplo de el archivo en sí

lo tanto, aquí va la ejemplos de uso simplificado:

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 

} 

En mi caso los avances plantean muy bien de izquierda a derecha sin saltos anormales. Ajuste el umbral para un equilibrio óptimo entre el rendimiento y la capacidad de respuesta. Demasiado pequeño y la velocidad de lectura puede más que duplicar en dispositivos pequeños, demasiado grande y el progreso no sería fluido.

Espero que ayude. ¡Siéntete libre de editar si encontraste errores o errores tipográficos, o vota para enviarme algunos estímulos!: D

+0

¡Excelente! Exactamente lo que estaba buscando, lo adaptaré, ¡gracias! :) – Matthieu

Cuestiones relacionadas