2015-10-20 3 views
5

シナリオ:極端な低速ネットワークを介して巨大なXMLファイルを受信して​​いますので、できるだけ早く過度の処理を開始します。そのため、私はSAXParserを使うことにしました。なぜSAXParserはイベントをスローする前にあまり読み込みますか?

タグが完成した後、イベントが発生すると予想しました。

次のテストは、私が何を意味するかを示しています。

@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); 
     } 
    }); 
} 

私はイベントが発生したときに読んでいるものを参照して入力ストリームを包みました。

<a>     <- output from read() 
Handler start: a 
<b>     <- output from read() 
Handler start: b 
</b>     <- output from read() 
Handler end: b 
... 

残念ながら結果は以下ました:私はこのようなものだったと予想何

<a> <b>..</b> <c>..</c></a>  <- output from read() 
Handler start: a 
Handler start: b 
Handler end: b 
Handler start: c 
Handler end: c 
Handler end: a 

どこで私のミスとどのように私は期待される結果を得ることができますか?

編集:

  • まず最初は、彼はすべてをスキャンする原因となるドキュメントのバージョンを検出しようとしているということです。彼は間にブレークインします(しかし、私が期待するところではありません)
  • このストリームにはこれほど多くのものが含まれていない可能性があるため、例えば1000バイトとブロックを読みたいとは思っていません時間点。
  • IはXMLEntityManagerにおけるバッファサイズが見つかりました:
    • のpublic static final int型DEFAULT_BUFFER_SIZE = 8192。
    • パブリックstatic final int DEFAULT_XMLDECL_BUFFER_SIZE = 64;
    • パブリックstatic final int DEFAULT_INTERNAL_BUFFER_SIZE = 1024;
+1

は、私はあなたの時間を浪費テストファイルを試してみるべきだと思いますが、大きなファイルを使用する場合あなたはあなたが期待するような何かを得るかもしれません。 – Elemental

答えて

2

それはあなたが方法についての間違った仮定を作っているようですI/Oは機能します。ほとんどのソフトウェアと同様に、XMLパーサは、ストリームから1バイトを要求するとパフォーマンスが低下するため、データをチャンクで要求します。

これは、読み取り試行が返される前にバッファーを完全に埋める必要があるという意味ではありません。ただ、ByteArrayInputStreamはネットワークの動作をエミュレートできません。InputStreamread(byte[], int, int)をオーバーライドして完全なバッファを返さずに簡単に修正できます。すべてのリクエストに応じてシングルバイト:これは、XMLパーサがInputStreamからのデータの可用性に適応する方法、

<a> 
Handler start: a<b> 
Handler start: b..</b> 
Handler end: b <c> 
Handler start: c..</c> 
Handler end: c</a> 
Handler end: a? 

上映を出力します

@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); 
     } 
    }); 
} 

。私はそれが(例えば)1Kチャンクまたは何にファイルをバッファになるので、それが処理を開始する前に、バッファの読み取りが効果的にファイル全体を読んでいると思われる - -

+2

'read(byte []、int、int)'は 'return super.read(b、off、1);'で簡略化できます。 –

+0

@Didier L:確かに、良いキャッチ。 – Holger

1

内部的にはSAXパーサーは、おそらくBufferedReaderであなたのInputStreamをラップまたは緩衝のいくつかの並べ替えを使用しています。それ以外の場合は、入力から1バイトを読み込むため、実際にパフォーマンスが低下します。

だから、何を見ていることは、パーサがその上の入力からチャンクを読み取り、その部分を処理し、SAXイベントを発行し、ということである...

関連する問題