2

私は、TCPソケットを介してJavaサーバーからxmlデータの継続ストリームを読み取るAndroidクライアントで作業しています。サーバーは、連続する応答間の区切り文字として「\n」文字を送信します。以下にモデルの実装を示します。

<response1>
   <datas>
      <data>
           .....
           .....
      </data>
      <data>
           .....
           .....
      </data>
      ........
      ........
   </datas>
</response1>\n    <--- \n acts as delimiter ---/> 
<response2>

   <datas>
      <data>
           .....
           .....
      </data>
      <data>
           .....
           .....
      </data>
      ........
      ........
   </datas>
</response2>\n

さて、構造が明確になったことを願っています。この応答は、圧縮されたサーバーzlibから送信されます。したがって、最初にサーバーから読み取ったものをすべて膨らませ、区切り文字を使用して応答を分離し、解析する必要があります。そして、私はSAXを使用してXMLを解析しています

今、私の主な問題は、サーバーからのxml応答が非常に大きくなる可能性があることです(3〜4 MBの範囲になる可能性があります)。それで

  • 区切り文字に基づいて応答を区切るには(\ n) stringBuilderを使用して、ソケットから読み取る応答ブロックを格納する必要があります。一部の電話では、StringBuilderはメガバイト範囲の文字列を格納できません。OutOfMemory例外が発生しているため、このようなスレッドから、(一時的にでも)大きな文字列を保持することはあまり良い考えではないことがわかりました。

  • 次に、inflatorReadStream(ソケット入力ストリームからデータを取得します)をSAXパーサーの入力ストリームとして渡そうとしました(自分でxmlを分離することなく、タグに基づいてドキュメントの終わりを見つけるSAXの機能に依存することはありません)。今回は1つの応答が正常に解析されますが、'\ n'区切り文字を見つけると、SAXはドキュメント要素の後にジャンクと言って ExpatParserParseExceptionをスローします。

  • そのExpatParserParseExceptionをキャッチした後、もう一度読み取ろうとしましたが、例外をスローした後、SAXパーサーはストリームを閉じるため、再度読み取り/解析しようとすると、入力ストリームが閉じていることを示すIOExceptionが発生します。

私が行ったことのコードスニペットを以下に示します(わかりやすくするために、関連のないすべてのtry catchブロックを削除しました)。

private Socket clientSocket     =   null;
DataInputStream readStream      =   null;
DataOutputStream writeStream        =   null;
private StringBuilder incompleteResponse    =   null;
private AppContext  context     =   null;


public boolean connectToHost(String ipAddress, int port,AppContext myContext){
        context                     =   myContext;
        website                     =   site;
        InetAddress serverAddr          =   null;

    serverAddr                      =   InetAddress.getByName(website.mIpAddress);

    clientSocket                    =   new Socket(serverAddr, port);

    //If connected create a read and write Stream objects..
    readStream   =  new DataInputStream(new InflaterInputStream(clientSocket.getInputStream()));
    writeStream             =   new DataOutputStream(clientSocket.getOutputStream());

    Thread readThread = new Thread(){
            @Override
            public void run(){                              
            ReadFromSocket();                   
        }
    };
    readThread.start();     
    return true;
}


public void ReadFromSocket(){
   while(true){
       InputSource xmlInputSource = new InputSource(readStream);
       SAXParserFactory spf =   SAXParserFactory.newInstance();
       SAXParser sp =   null;
       XMLReader xr =   null;
       try{
           sp   = spf.newSAXParser();
       xr   = sp.getXMLReader();
       ParseHandler xmlHandler =    new ParseHandler(context.getSiteListArray().indexOf(website), context);
       xr.setContentHandler(xmlHandler);
       xr.parse(xmlInputSource);
   //  postSuccessfullParsingNotification();
       }catch(SAXException e){
           e.printStackTrace();
           postSuccessfullParsingNotification();
       }catch(ParserConfigurationException e){
           e.printStackTrace();
           postSocketDisconnectionBroadcast();
           break;
       }catch (IOException e){
           postSocketDisconnectionBroadcast();
           e.printStackTrace();
           e.toString();
           break;
       }catch (Exception e){
           postSocketDisconnectionBroadcast();
           e.printStackTrace();
           break;
       }
    }
}

そして今、私の質問は

  1. SAXパーサーがxml応答後にジャンク文字を無視し、例外をスローしてストリームを閉じないようにする方法はありますか?
  2. そうでない場合は、stringBuilderのメモリ不足エラーを回避する方法はありません。率直に言って、私はこれについて肯定的な答えを除いていません。回避策はありますか?
4

2 に答える 2

2
  1. 改行を検出してパーサーを閉じ、ストリームを続行する新しいパーサーを起動するフィルターに渡すリーダーまたはストリームの周りにラッパーを使用できる場合があります。ストリームは有効な XML ではなく、そうではありません。現在実装しているように解析できます。http://commons.apache.org/io/api-release/org/apache/commons/io/input/CloseShieldInputStream.htmlを見てください。
  2. いいえ。
于 2011-08-16T05:54:50.387 に答える
1

SAXパーサーがプッシュモデル(生データチャンクを自分でプッシュし、生データを解析するときにイベントを発生させる)をサポートしている場合は、SAXセッションの開始時に独自の初期XMLタグをプッシュするだけです。これが最上位のドキュメントタグになり、受信時に応答をプッシュできます。SAXに関する限り、応答は第2レベルのタグになります。そうすれば、同じSAXセッションで複数の応答をプッシュでき、OnTagOpenイベント(または使用しているウィート)で、レベル1でタグ名を検出したときに新しい応答がいつ開始されるかがわかります。

于 2011-08-16T23:37:07.273 に答える