【问题标题】:Best approach to serialize XML to stream with Java?序列化 XML 以使用 Java 流式传输的最佳方法?
【发布时间】:2010-12-27 01:47:30
【问题描述】:

我们使用 XStream 对 XML 进行序列化/反序列化...并且刚刚得到一个 OutOfMemory 异常。

首先,我不明白为什么会出现错误,因为我们有 500MB 分配给服务器。

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

目前我们有大约 60K 个对象,每个对象大约 50 个字节。我们将 60K POJO 加载到内存中,并将它们序列化为一个字符串,我们使用 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 存储在内存中,将内容写入单个字符串。相反,我们应该将单个 &lt;data&gt; POJO 写入流。 XStream supports this 但似乎不支持 &lt;meta&gt; 元素。数据需要采用以下形式:

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

    [thousands of <data>]
</root>

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

【问题讨论】:

  • 你怎么知道每个对象是50字节?
  • 只是一个近似值。有五个字段,每个字段包含大约 10 个字节的数据..
  • 我指的只是数据。我不知道 Java 使用多少内存来存储对象本身。我还没有使用分析器..
  • 您链接到的页面提供了编写流序列化所需的代码的问题在哪里。我唯一不明白的是你的意思是&lt;meta&gt; 将不被支持。这是什么意思。
  • 我相信 XStream 只支持序列化同一类的对象集合。所以你不能序列化data类对象meta类对象。

标签: java xml web-services stream xstream


【解决方案1】:

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

阅读方面当然也是如此。不要将 XML 读入字符串并要求 XStream 从该字符串反序列化:直接从 InputStream 反序列化。

您提到了第二个问题,即无法序列化 &lt;meta&gt; 元素和 &lt;data&gt; 元素。我不认为这是一个 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>

我也成功序列化和反序列化嵌套列表。

【讨论】:

    【解决方案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();
    

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

        使用XMLStreamWriter(或XStream)来序列化它,你可以在上面写任何你想要的东西。如果您可以选择获取输入流而不是整个字符串,请使用 SAXParser,它是基于事件的,尽管实现可能有点笨拙,但您将能够读取向您抛出的任何 XML,甚至如果 XML 很大(我已经使用 SAXParser 解析了 2GB 以上的 XML 文件)。

        顺便说一句,您应该将二进制数据而不是字符串发送到 XML 解析器。 XML 解析器将通过 XML 序列开头的 xml 标记读取接下来要出现的字节数组的编码:

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

        一个字符串已经被编码了。更好的做法是让 XML 在用它创建字符串之前解析原始流。

        【讨论】:

        • 更好的是使用Stax解析器(或xpp,它的前身);增量(流)解析,但使用起来不那么麻烦。更好的是,Xstream 已经允许人们使用它。
        猜你喜欢
        • 2010-12-30
        • 1970-01-01
        • 1970-01-01
        • 2018-07-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多