序列化XML以使用Java进行流式传输的最佳方法?

时间:2009-12-16 01:48:54

标签: java xml web-services stream xstream

我们使用XStream对XML进行序列化/反序列化......并且只获得了OutOfMemory异常。

首先,我不明白为什么我们收到错误,因为我们已经为服务器分配了500MB。

问题是 - 我们应该做出哪些改变以避免麻烦?我们希望确保此实施规模。

目前我们有~60K个对象,每个~50个字节。我们在内存中加载60K POJO,并将它们序列化为一个String,我们使用HttpClient发送给Web服务。接收时,我们获取整个String,然后转换为POJO。 XML /对象层次结构如下:

<root>
    <meta>
       <date>10/10/2009</date>
       <type>abc</type>
    </meta>

    <data>
        <field>x</field>
    </data>

    [thousands of <data>]
</root>

我收集最好的方法是将POJO存储在内存中,将内容写入单个String。相反,我们应该将单个<data> POJO写入流。 XStream supports这似乎不支持<meta>元素。数据需要采用以下形式:

<root> 
    <data>
        <field>x</field>
    </data>

    [thousands of <data>]
</root>

那么什么方法最容易流式传输整个树?

4 个答案:

答案 0 :(得分:3)

您肯定希望避免将POJO序列化为庞大的字符串,然后将该字符串写出来。使用XStream API将POJO直接序列化到OutputStream。今年早些时候,当我发现我生成200-300Mb的XML文档并获得OutOfMemoryErrors时,我遇到了同样的情况。切换非常容易。

当然对于阅读方而言同样如此。不要将XML读入String并要求XStream从该String反序列化:直接从InputStream反序列化。

您提到了第二个问题,即无法序列化<meta>元素和<data>元素。我不认为这是一个XStream问题或限制因为我按照以下顺序常规地序列化更复杂的结构:

<myobject>
    <item>foo</item>
    <anotheritem>foo</anotheritem>
    <alist>
        <alistitem>
            <value1>v1</value1>
            <value2>v2</value2>
            <value3>v3</value3>
            ...
        </alistitem>
        ...
        <alistitem>
            <value1>v1</value1>
            <value2>v2</value2>
            <value3>v3</value3>
            ...
        </alistitem>
    </alist>
    <anotherlist>
        <anotherlistitem>
            <valA>A</valA>
            <valB>B</valB>
            <valC>C</valC>
            ...
        </anotherlistitem>
        ...
    </anotherlist>
</myobject>

我也成功地对嵌套列表进行了序列化和反序列化。

答案 1 :(得分:2)

不确定这里的问题是什么......你在那个网页上找到了答案。

您提供的链接上的示例代码建议:

Writer someWriter = new FileWriter("filename.xml");

ObjectOutputStream out = xstream.createObjectOutputStream(someWriter, "root");
out.writeObject(dataObject);
// iterate over your objects...
out.close();

并且阅读几乎完全相同但是使用Reader for Writer和Input for Output:

Reader someReader = new FileReader("filename.xml");

ObjectInputStream in = xstream.createObjectInputStream(someReader);
DataObject foo = (DataObject)in.readObject();
// do some stuff here while there's more objects...
in.close();

答案 2 :(得分:0)

我建议使用Visual VMEclipse Memory Analyzer等工具来确保您没有内存泄漏/问题。

另外,你怎么知道每个对象是50个字节?这听起来不太可能。

答案 3 :(得分:0)

使用XMLStreamWriter(或XStream)对其进行序列化,您可以在其上编写任何内容。如果您可以选择获取输入流而不是整个字符串,请使用SAXParser,它是基于事件的,虽然实现可能有点笨拙,但您将能够读取任何抛出的XML,甚至如果XML很大(我用SAXParser解析了2GB以上的XML文件)。

正如旁注,您应该将二进制数据而不是字符串发送到XML解析器。 XML解析器将读取将在XML序列的开头通过xml标记接下来的字节数组的编码:

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>

字符串已经被编码。最好让XML在使用它创建String之前解析原始流。