Java에서 SAX 파서를 작성하여 위키피디아 기사의 2.5GB XML 파일을 구문 분석합니다. 자바에서 파싱 진행 상황을 모니터링 할 수있는 방법이 있습니까?Java SAX 파서 진행 모니터링
답변
사용하십시오 javax.swing.ProgressMonitorInputStream.
기사 수를 알고 있다고 가정하면 처리기에 카운터를 보관할 수 없습니까? 예 :
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 센트
나는 그것을 알아 냈다. 그러나 기사를 세지 않아도되는 방법을 찾고 있었다. 파일에 파서의 위치를 알아낼 수있는 방법이 있다고 생각했습니다. 파일 크기를 쉽게 얻을 수 있기 때문입니다. – Danijel
당신은 방법 org.xml.sax.helpers.DefaultHandler/BaseHandler
의 setDocumentLocator
를 재정 의하여 파일에서 현재 행/열의 추정치를 얻을 수 있습니다. 이 메서드는 필요한 경우 현재 줄/열의 근사값을 얻을 수있는 개체와 함께 호출됩니다.
편집 : 내 지식으로는 절대적인 입장을 취할 표준 방법이 없습니다. 그러나 일부 SAX 구현은 이러한 종류의 정보를 제공합니다.
닫기,하지만 파일의 줄 수를 알아야합니다. 맞습니까? – Danijel
참으로. 수수께끼 같은 EJP에 의해 또 다른 아이디어가 지적되었을 수도 있습니다. 입력 스트림의 진행을 사용하여 진행 상황을 예측할 수 있습니다. 그러나 잠재적 인 버퍼링 및 미리보기 때문에 파싱의 진행이 아닙니다. –
내가 입력 스트림 위치를 사용하십시오. "진짜"클래스에서 위임/상속받은 독창적 인 스트림 클래스를 만들고 읽은 바이트를 추적합니다. 말했듯이 전체 파일 크기를 쉽게 구할 수 있습니다. 나는 버퍼링, 미리보기, 등등에 대해 걱정하지 않을 것입니다 - 이것들과 같은 대용량 파일은 닭 먹이입니다. 반면에, 나는 "99 %"로 위치를 제한 할 것입니다.
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
우수! 정확히 내가 무엇을 찾고 있었는지, 나는 그것에 적응할 것이다, 고마워! :) – Matthieu
나는 이것이 충분히 가깝다고 생각한다. 감사! – Danijel
어떤 대답이라도 간단할까요?! :) – Matthieu