2010-06-23 7 views

Odpowiedz

9

Użyj javax.swing.ProgressMonitorInputStream.

+0

Myślę, że to będzie wystarczająco blisko. Dzięki! – Danijel

+0

Czy jakakolwiek odpowiedź może być prostsza ?! :) – Matthieu

1

Zakładając, że wiesz, ile artykułów posiadasz, nie możesz po prostu zachować licznika w programie obsługi? Na przykład.

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

(nie wiem, czy analizowania „artykuł”, to tylko przykład)

Jeśli nie znasz numeru artykułu z góry, trzeba go najpierw policzyć . Następnie możesz wydrukować status nb tags read/total nb of tags, powiedz każdy 100 znaczników (counter % 100 == 0).

A może nawet inny wątek monitoruje postęp. W takim przypadku możesz chcieć zsynchronizować dostęp do licznika, ale nie jest to konieczne, ponieważ nie musi być naprawdę dokładne.

Moje 2 centów

+0

Wymyśliłem to, ale szukałem sposobu na zrobienie tego bez potrzeby liczenia artykułów w pierwszej kolejności. Pomyślałem, że może istnieje sposób, aby dowiedzieć się pozycji parsera w pliku, ponieważ mogę łatwo uzyskać rozmiar pliku. – Danijel

2

Można uzyskać szacunkową wartość bieżącego wiersza/kolumny w pliku poprzez nadpisanie metody setDocumentLocator z org.xml.sax.helpers.DefaultHandler/BaseHandler. Ta metoda jest wywoływana z obiektem, z którego w razie potrzeby można uzyskać przybliżenie bieżącej linii/kolumny.

Edycja: Zgodnie z moją wiedzą, nie ma standardowego sposobu uzyskania absolutnej pozycji. Jestem jednak pewien, że niektóre implementacje SAX oferują tego rodzaju informacje.

+0

Zamknij, ale wtedy musiałbym znać liczbę linii w pliku, prawda? – Danijel

+0

Rzeczywiście. Inna idea mogłaby zostać wskazana przez enigmatyczny EJP. Możesz oszacować postęp, korzystając z zaawansowania w strumieniu wejściowym. Jednak nie jest to również postęp w analizie składniowej, ze względu na potencjalne buforowanie i wyprzedzanie. –

0

użyję pozycję strumienia wejściowego. Stwórz własną banalną klasę strumieniową, która deleguje/dziedziczy po "prawdziwym" i śledzi czytanie bajtów. Jak mówisz, uzyskanie całkowitego rozmiaru pliku jest łatwe. Nie martwiłbym się o buforowanie, wyprzedzanie itp. - w przypadku dużych plików, takich jak te, jest to karma dla kurcząt. Z drugiej strony ograniczyłbym pozycję do "99%".

10

Dzięki sugestii EJP o ProgressMonitorInputStream, w końcu rozszerzyłem FilterInputStream, dzięki czemu ChangeListener może być użyte do monitorowania aktualnej pozycji odczytu w terminach bajtów.

Dzięki temu masz lepszą kontrolę, na przykład, aby pokazać wiele pasków postępu dla równoległego odczytu dużych plików xml. Właśnie to zrobiłem.

więc uproszczona wersja do monitorowania strumienia:

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

nie wie - czy opieki - jak duży strumień bazowy jest, więc trzeba je zdobyć w inny sposób, na przykład z sam plik.

Więc tu idzie uproszczoną wykorzystanie próbki:

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 

} 

W moim przypadku postępy jego podniesienie ładnie od lewej do prawej bez nieprawidłowych skoków. Dostosuj próg, aby uzyskać optymalną równowagę między wydajnością i reakcją. Zbyt mała i prędkość odczytu może się podwoić na małych urządzeniach, zbyt dużych, a postępy nie byłyby płynne.

Mam nadzieję, że to pomaga. Jeśli znajdziesz błędy lub literówki lub zagłosuj, aby przesłać mi zachęty, możesz je edytować.: D

+0

Doskonale! Dokładnie tego, czego szukałem, dostosuję to, dzięki! :) – Matthieu