Java 为什么SAXParser在抛出事件之前读了这么多?
场景:我通过极慢的网络接收到一个巨大的xml文件,所以我希望尽早开始过度处理。因此,我决定使用SAXParser 我希望在标记完成后,我会得到一个事件 下面的测试说明了我的意思:Java 为什么SAXParser在抛出事件之前读了这么多?,java,xml,stream,sax,saxparser,Java,Xml,Stream,Sax,Saxparser,场景:我通过极慢的网络接收到一个巨大的xml文件,所以我希望尽早开始过度处理。因此,我决定使用SAXParser 我希望在标记完成后,我会得到一个事件 下面的测试说明了我的意思: @Test public void sax_parser_read_much_things_before_returning_events() throws Exception{ String xml = "<a>" + " <b>..</b>
@Test
public void sax_parser_read_much_things_before_returning_events() throws Exception{
String xml = "<a>"
+ " <b>..</b>"
+ " <c>..</c>"
// much more ...
+ "</a>";
// wrapper to show what is read
InputStream is = new InputStream() {
InputStream is = new ByteArrayInputStream(xml.getBytes());
@Override
public int read() throws IOException {
int val = is.read();
System.out.print((char) val);
return val;
}
};
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse(is, new DefaultHandler(){
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
System.out.print("\nHandler start: " + qName);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
System.out.print("\nHandler end: " + qName);
}
});
}
@测试
public void sax\u解析器\u在返回\u events()引发异常之前读取\u much\u things\u{
字符串xml=“”
+ " .."
+ " .."
//更多。。。
+ "";
//包装器以显示所读内容
InputStream is=新的InputStream(){
InputStream is=newbytearrayinputstream(xml.getBytes());
@凌驾
public int read()引发IOException{
int val=is.read();
系统输出打印((字符)val);
返回val;
}
};
SAXParser parser=SAXParserFactory.newInstance().newSAXParser();
parser.parse(是新的DefaultHandler()){
@凌驾
public void startElement(字符串uri、字符串localName、字符串qName、属性)引发SAXException{
System.out.print(“\n引导程序开始:“+qName”);
}
@凌驾
public void endElement(字符串uri、字符串localName、字符串qName)引发SAXException{
System.out.print(“\nHandler end:+qName”);
}
});
}
我包装了输入流以查看读取的内容以及事件发生的时间
我所期望的是这样的:
<a> <- output from read()
Handler start: a
<b> <- output from read()
Handler start: b
</b> <- output from read()
Handler end: b
...
在内部,SAX解析器很可能已将您的输入流包装在缓冲读取器中
或使用某种缓冲。否则它将从输入中读取单个字节,这将真正影响性能
因此,您看到的是解析器从输入中读取一个块,然后处理该部分,发出SAX事件,等等…似乎您对I/O的工作方式做出了错误的假设。与大多数软件一样,XML解析器将请求数据块,因为从流中请求单个字节会导致性能灾难
这并不意味着在读取尝试返回之前缓冲区必须完全填满。只是,ByteArrayInputStream
无法模拟网络InputStream
的行为。您可以通过覆盖读取(byte[],int,int)
而不返回完整的缓冲区,例如每个请求返回一个字节,轻松解决此问题:
@Test
public void sax_parser_read_much_things_before_returning_events() throws Exception{
final String xml = "<a>"
+ " <b>..</b>"
+ " <c>..</c>"
// much more ...
+ "</a>";
// wrapper to show what is read
InputStream is = new InputStream() {
InputStream is = new ByteArrayInputStream(xml.getBytes());
@Override
public int read() throws IOException {
int val = is.read();
System.out.print((char) val);
return val;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
return super.read(b, off, 1);
}
};
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse(is, new DefaultHandler(){
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
System.out.print("\nHandler start: " + qName);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
System.out.print("\nHandler end: " + qName);
}
});
}
@测试
public void sax\u解析器\u在返回\u events()引发异常之前读取\u much\u things\u{
最后一个字符串xml=“”
+ " .."
+ " .."
//更多。。。
+ "";
//包装器以显示所读内容
InputStream is=新的InputStream(){
InputStream is=newbytearrayinputstream(xml.getBytes());
@凌驾
public int read()引发IOException{
int val=is.read();
系统输出打印((字符)val);
返回val;
}
@凌驾
公共整数读取(字节[]b,整数关闭,整数长度)引发IOException{
返回super.read(b,off,1);
}
};
SAXParser parser=SAXParserFactory.newInstance().newSAXParser();
parser.parse(是新的DefaultHandler()){
@凌驾
public void startElement(字符串uri、字符串localName、字符串qName、属性)引发SAXException{
System.out.print(“\n引导程序开始:“+qName”);
}
@凌驾
public void endElement(字符串uri、字符串localName、字符串qName)引发SAXException{
System.out.print(“\nHandler end:+qName”);
}
});
}
这会打印出来
处理程序启动:一个
处理程序开始:b。。
处理器端:b
处理程序开始:c。。
处理器端:c
处理程序结束:a?
显示XML解析器如何适应来自InputStream
的数据可用性我认为您应该尝试bugger测试文件-我怀疑缓冲读取在开始处理之前有效地读取了整个文件,因为它会将文件缓冲(例如)1k块或任何东西-如果你使用一个大文件,你可能会得到更像你期望的东西。read(byte[],int,int)
可以简化为return super.read(b,off,1)代码>。
@Test
public void sax_parser_read_much_things_before_returning_events() throws Exception{
final String xml = "<a>"
+ " <b>..</b>"
+ " <c>..</c>"
// much more ...
+ "</a>";
// wrapper to show what is read
InputStream is = new InputStream() {
InputStream is = new ByteArrayInputStream(xml.getBytes());
@Override
public int read() throws IOException {
int val = is.read();
System.out.print((char) val);
return val;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
return super.read(b, off, 1);
}
};
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse(is, new DefaultHandler(){
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
System.out.print("\nHandler start: " + qName);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
System.out.print("\nHandler end: " + qName);
}
});
}