我的servlet的doPost()接收一个HttpServlet请求,其servlet InputStream向我发送了一大块用XML包装的uuencoded数据。例如,有一个元素:
<filedata encoding="base64">largeChunkEncodedHere</filedata>
我需要解码块并将其写入文件。我想从区块中获得一个InputStream,使用MimeUtility将其解码为流,并使用该流来写入文件——我不想将这个大区块读取到内存中。
XML是扁平的;即没有太多嵌套。我的第一个想法是使用SAX解析器,但我不知道如何切换到流来只读取块。
谢谢你的想法。
格伦
编辑1:注意JB Nizet在这篇文章中的悲观回答。
编辑2:我在下面肯定地回答了我自己的问题,并在下面标记maximdim的回答是正确的,尽管它没有完全回答这个问题,但它确实引导我使用StAX API和Woodstox。
Woodstox还有一个建议:它还可以从内部高效地解码base64编码的内容。为此,您需要将XMLStreamReader
强制转换为XMLStreamReader2
(或TypedXMLStreamReader
),这是Stax2扩展API的一部分。
但有了它,就可以得到自动处理Base64解码的方法readElementAsBinary()
和getElementAsBinary()
。CCD_ 6类似地具有用于写入二进制数据的Base64编码方法。
您可以使用SAX过滤器或XPath只获取您感兴趣的元素。一旦您有了元素的内容,就将其传递给MimeUtility.decode()并将流写入文件。
我建议您用代码示例更新您的问题,并让我们知道哪些不起作用。
更新:
以下是使用StaX2解析器(Woodstox)的示例代码。出于某种原因,JDK中包含的StaX解析器似乎并没有类似的getText()方法,至少在快速浏览时是这样。
显然,input(r)和output(w)可以是任何Reader/Writer或Stream——这里仅以String为例。
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);
以下是解析时如何从元素流式传输的一些详细信息使用Woodstox框架,StAX是可能的。
这篇文章有一个很好的概述。
从XMLInputFactory,我们可以调用createXMLStreamReader(java.io.InputStream流)。这将返回一个XMLStreamReader2有一个getText(Writer w,boolean preserveContents)方法,该方法为写入的字节数。必须实施此方法。在实现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测试中,TestGetSegmentedTexttestSegmentedGetCharacters()方法我们看到一个sr.getTextCharacters(offset,start,len)方法。事实上,多参数的javadocgetTextCharacters()显示了以下实现。
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;
}
}