2010-06-23 2 views
11

Java에서 SAX 파서를 작성하여 위키피디아 기사의 2.5GB XML 파일을 구문 분석합니다. 자바에서 파싱 진행 상황을 모니터링 할 수있는 방법이 있습니까?Java SAX 파서 진행 모니터링

답변

9

사용하십시오 javax.swing.ProgressMonitorInputStream.

+0

나는 이것이 충분히 가깝다고 생각한다. 감사! – Danijel

+0

어떤 대답이라도 간단할까요?! :) – Matthieu

1

기사 수를 알고 있다고 가정하면 처리기에 카운터를 보관할 수 없습니까? 예 :

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

당신이 사전에 문서 번호를 모르는 경우

것은, 당신이 먼저 계산해야합니다 (당신은 "글을"구문 분석되어 있는지 나도 몰라, 그냥 예입니다) . 그런 다음 상태 nb tags read/total nb of tags을 인쇄 할 수 있으며 각 100 개의 태그 (counter % 100 == 0)를 말하십시오.

또는 다른 스레드에서 진행 상황을 모니터링 할 수도 있습니다. 이 경우 카운터에 대한 액세스를 동기화하고 싶지만 실제로는 정확할 필요는 없다는 점에서 필요하지는 않습니다.

내 2 센트

+0

나는 그것을 알아 냈다. 그러나 기사를 세지 않아도되는 방법을 찾고 있었다. 파일에 파서의 위치를 ​​알아낼 수있는 방법이 있다고 생각했습니다. 파일 크기를 쉽게 얻을 수 있기 때문입니다. – Danijel

2

당신은 방법 org.xml.sax.helpers.DefaultHandler/BaseHandlersetDocumentLocator를 재정 의하여 파일에서 현재 행/열의 추정치를 얻을 수 있습니다. 이 메서드는 필요한 경우 현재 줄/열의 근사값을 얻을 수있는 개체와 함께 호출됩니다.

편집 : 내 지식으로는 절대적인 입장을 취할 표준 방법이 없습니다. 그러나 일부 SAX 구현은 이러한 종류의 정보를 제공합니다.

+0

닫기,하지만 파일의 줄 수를 알아야합니다. 맞습니까? – Danijel

+0

참으로. 수수께끼 같은 EJP에 의해 또 다른 아이디어가 지적되었을 수도 있습니다. 입력 스트림의 진행을 사용하여 진행 상황을 예측할 수 있습니다. 그러나 잠재적 인 버퍼링 및 미리보기 때문에 파싱의 진행이 아닙니다. –

0

내가 입력 스트림 위치를 사용하십시오. "진짜"클래스에서 위임/상속받은 독창적 인 스트림 클래스를 만들고 읽은 바이트를 추적합니다. 말했듯이 전체 파일 크기를 쉽게 구할 수 있습니다. 나는 버퍼링, 미리보기, 등등에 대해 걱정하지 않을 것입니다 - 이것들과 같은 대용량 파일은 닭 먹이입니다. 반면에, 나는 "99 %"로 위치를 제한 할 것입니다.

10

EJP가 제안한 ProgressMonitorInputStream 덕분에 ChangeListener을 사용하여 바이트 단위로 모니터링 할 수 있도록 FilterInputStream을 확장했습니다.

이 기능을 사용하면 큰 xml 파일을 병렬로 읽을 수있는 여러 진행 막대를 표시 할 수 있습니다. 정확히 내가 한 일입니다.

그래서

, 모니터 할 수있는 스트림의 단순화 된 버전 :

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

그것은 알 수 없습니다 - 또는 관리 - 기본이되는 스트림이 얼마나 큰, 그래서 당신은에서, 그것은 몇 가지 다른 방법으로 얻을 필요 파일 자체. 비정상적인 점프없이 왼쪽에서 오른쪽으로 진행되면서 멋지게 인상 내 경우에는

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 

} 

:

그래서, 여기에 간단한 샘플 사용을 간다. 성능과 응답 사이의 최적 균형에 대한 임계 값을 조정하십시오. 너무 작고 읽기 속도가 작은 장치에서 두 배 이상으로 커질 수 있습니다. 너무 커서 진행이 원활하지 않습니다.

희망이 있습니다. 실수 나 오타가있는 경우 언제든지 편집하거나 투표를 통해 격려를 보내주십시오!: D

+0

우수! 정확히 내가 무엇을 찾고 있었는지, 나는 그것에 적응할 것이다, 고마워! :) – Matthieu