2012-02-22 115 views
1

我的servlet的doPost()接收到一個HttpServletRequest,它的ServletInputStream向我發送了大量用XML封裝的uuencoded數據。例如,有一個元素:從XML元素內容中獲取InputStream

<filedata encoding="base64">largeChunkEncodedHere</filedata> 

我需要解碼塊並將其寫入文件。我想從塊中獲取InputStream,使用MimeUtility將其解碼爲流,然後使用該流寫入文件---我不希望將這個大塊讀入內存。

XML是平坦的;即沒有太多嵌套。我的第一個想法是使用SAX解析器,但我不知道如何切換到流來讀取塊。

感謝您的想法。

格倫

編輯1:注JB Nizet在this post悲觀的答案。

編輯2:我肯定低於回答我自己的問題,並標註以下爲正確maximdim的答案,儘管它並不完全回答這個問題,它沒有直接我到StAX API和Woodstox。

+0

不清楚你想完成什麼。如果您正確使用Streams,則不應將數據同時保存在內存中。另一方面,我認爲你的情況並不重要,因爲瀏覽器/客戶端可能會在POST中將整個數據提交給你的servlet,然後你纔有機會處理它,所以它應該不會有太大影響,因爲整個數據將會已經在你身邊的記憶中。 – maximdim 2012-02-22 17:54:25

+0

@maximdim問題是關於正確使用流。使用兩倍的內存在這種情況下有所不同。 – Glenn 2012-02-22 19:41:58

回答

0

你可以使用SAX filter或XPath來獲得你感興趣的元素。一旦你有元素的內容,將它傳遞給MimeUtility.decode()並將流寫入文件。

我建議你用代碼示例更新你的問題,讓我們知道什麼是行不通的。

更新:

下面是使用StaX2解析器(Woodstox)的樣本代碼。出於某種原因,包含在JDK中的StaX解析器似乎沒有可比較的getText()方法,至少快速瀏覽一下。

顯然,輸入(r)和輸出(w)可以是任何讀寫器或流 - 使用字符串就在這裏舉個例子。

Reader r = new StringReader("<foo><filedata encoding=\"base64\">largeChunkEncodedHere</filedata></foo>"); 
    Writer w = new StringWriter(); 

    XMLInputFactory2 xmlif = (XMLInputFactory2)XMLInputFactory2.newInstance(); 
    XMLStreamReader2 sr = (XMLStreamReader2)xmlif.createXMLStreamReader(r); 

    boolean flag = false; 
    while (sr.hasNext()) { 
     sr.next(); 
     if (sr.getEventType() == XMLStreamConstants.START_ELEMENT) { 
      if ("filedata".equals(sr.getLocalName())) { 
       flag = true; 
      } 
     } 
     else if (sr.getEventType() == XMLStreamConstants.CHARACTERS) { 
      if (flag) { 
       sr.getText(w, false); 
       break; 
      } 
     } 
    } 
    System.out.println(w); 
+0

謝謝。我會看看,但似乎「SAX過濾器」不返回流 - 這是這個問題的關鍵。問題不是現有代碼有什麼問題(沒有),但應該寫什麼代碼? – Glenn 2012-02-22 21:53:21

+0

好吧,我已經爲您使用StaX2解析器發佈了快速代碼示例 – maximdim 2012-02-23 13:54:31

+0

謝謝,雖然這並沒有涉及到它如何完成的基本原理,但它確實指向了我正確的方向。我已將細節放入自己的答案中。 – Glenn 2012-02-24 04:43:02

0

下面是關於如何從一個元素流在解析 使用StAX是可能的,使用Woodstox框架的一些細節。

this article有一個很好的概述。

從XMLInputFactory我們可以使用ServletInputStream調用createXMLStreamReader(java.io.InputStream stream)。這將返回一個XMLStreamReader2,其中 有一個getText(Writer w,boolean preserveContents)方法,該方法返回int的 寫入的字節數。該方法必須執行。在 實施Stax2ReaderImpl有此實現

// // // StAX2, Pass-through text accessors 
public int getText(Writer w, boolean preserveContents) 
    throws IOException, XMLStreamException 
{ 
    char[] cbuf = getTextCharacters(); 
    int start = getTextStart(); 
    int len = getTextLength(); 

    if (len > 0) { 
     w.write(cbuf, start, len); 
    } 
    return len; 
} 

在這段代碼中,我們需要改變getTextCharacters()方法,使其 從InputStream讀取。在Woodstox測試中TestGetSegmentedText testSegmentedGetCharacters()方法我們看到一個sr.getTextCharacters(offset,buf, start,len)方法的使用。實際上,多參數XMLStreamReader.getTextCharacters()的javadoc顯示了以下實現。

int length = 1024; 
char[] myBuffer = new char[ length ]; 
for (int sourceStart = 0 ; ; sourceStart += length) { 
    int nCopied = stream.getTextCharacters(sourceStart, myBuffer, 0, length); 
    if (nCopied < length) { 
     break; 
    } 
} 
0

對Woodstox還有一個建議:它還可以從內部有效地解碼base64編碼的東西。爲此,您需要將XMLStreamReader轉換爲XMLStreamReader2(或TypedXMLStreamReader),它是Stax2擴展API的一部分。

但是,通過這種方法,您可以獲得自動處理Base64解碼的方法readElementAsBinary()getElementAsBinary()XMLStreamWriter2類似地具有用於寫入二進制數據的Base64編碼方法。