使用有关持久性和 XML 的 InputStream 的最佳方式

Posted

技术标签:

【中文标题】使用有关持久性和 XML 的 InputStream 的最佳方式【英文标题】:Best way to use an InputStream regarding persistance and XML 【发布时间】:2010-10-12 21:44:30 【问题描述】:

我有一个 REST Web 服务,它侦听 POST 请求并从客户端获取 XML 有效负载并将其存储为最初的 InputStream 即 在您可以调用 getStream() 的 Representation 对象上

我想利用 InputStream 中保存的 XML,我开始认为保留它是明智的,因此我可以多次询问数据 - 因为一旦你阅读它,对象就会变为 null。所以我考虑将 InputStream 转换为字符串。这不是一个好主意,因为 javax.xml.parsers 库中的 DocumentBuilder.parse() 只允许您通过:

输入流 文件 网址 SAX 输入源

不是字符串。

关于从其中解析 XML,我应该在 InputStreams 中真正做些什么? 请记住,我将希望在以后的流程中通过代码重新询问该 XML。

【问题讨论】:

【参考方案1】:

如果您有一个 InputStream,并且想将其用作 XML 文档,那么您为什么不简单地解析它并传递 Document 对象呢?如果您想保留此对象,请使用序列化程序将其写回文本。

正如我在对 Tom Hawtin 的评论中指出的,编码在处理 XML 时非常重要。与其在这里写一篇可能会漏掉你的具体情况的长文,不如写一个article。

编辑:实际上,由于我的文章并没有专门讨论 Web 服务,所以我应该在这里深入探讨一下。有两个地方可以指定内容编码:在 XML 序言中,或在 Content-Type 响应标头中。根据 XML 规范,前者是您想要使用的,它是解析器将使用的。在大多数情况下,这无关紧要:由不了解规范的人设置的 Web 服务通常会使用没有字符集规范的 text/xml(这是不正确的,但可能不会造成伤害)。如果他们做的事情正确,他们将使用 utf-8 编码指定 application/xml。然而,你应该验证你得到了什么,这样你就不会得到一些解析器无法处理的奇怪编码。

【讨论】:

我认为在这里传递 Document 对象似乎是最轻松的事情 - 而且有点明显 - 抱歉,我认为我的大脑今天早上根本没有工作!【参考方案2】:

我建议使用 Apache Commons IO 库。 IOUtils 类包含许多将 InputStreams 转换为 String 的便捷方法,反之亦然。

【讨论】:

好建议。正如我在回答中所描述的那样,在自己阅读时节省了几行。 但我认为我不应该将其转换为字符串 - 那么 IOUtils 在这种情况下会有用吗? 除非您知道编码,否则不应转换为字符串。但是,IOUtils 也为您提供了 TeeInputStream,因此您可以将副本保存为字节。【参考方案3】:

通常,当我们谈论持久性时,我们谈论的是将其写入磁盘或其他媒体。那里的性能受到影响,您必须考虑磁盘空间问题。您需要权衡它与长期使用该 XML 的价值。

如果您只是在谈论将它保存在内存中(这听起来像您要问的那样),那么您可以分配一个字节数组,并将整个内容读入字节数组。您可以使用 ByteArrayInputStream 读取和重新读取该流。

这样做的成本是两倍。首先,您在内存中保存了一份副本,您需要根据您的可扩展性要求权衡它。其次,解析 XML 的成本有点高,所以最好尽可能只解析一次,然后将结果保存在一个对象中。

编辑:

要分配和读取字节数组,您可以经常(但不总是)依赖 InputStream 的 available() 方法来告诉您要分配多少。并用 DataInputStream 包装 InputStream,以便您可以调用 readFully() 将整个内容吸进字节数组中。

再次编辑:

阅读下面 Steen 的评论。他说得对,在这种情况下使用 available() 是个坏主意。

【讨论】:

我是一个实时环境,从不使用 available() 作为获取 Stream 的“大小”的方法。哎呀,你甚至不应该在你的后院使用它;) 改为使用我在此页面某处的详细帖子中描述的 read()(我永远无法习惯 ***s 浮动答案) 对 FileInputStream 使用很好,但对网络支持的流使用时会出现问题。在这种情况下,我没有足够强烈地表明我不愿意使用它。【参考方案4】:

如果要多次使用 XML,为什么不从 InputStream 中解析一次(这是繁重的工作),然后保留返回的 Document?

【讨论】:

【参考方案5】:

我认为您应该研究一些更适合保留编码的结构(即更多编码不可知论)。对于低级结构,请考虑byte[](但要小心内存释放!)或者您可以尝试设计适合您需要的数据类型。

您可以将InputStream 读入ByteArrayOutputStream(使用read() 方法之一)并从there 中提取byte[]

【讨论】:

【参考方案6】:

java.io.StringReader 将允许您使用InputSource

您可能希望将数据存储在byte[] 中,然后使用ByteArrayInputStream 读取。如果它特别大,您可能需要考虑压缩。这可以通过GzipInputStream 读出,通常应该包含在BufferedInputStream 中。

【讨论】:

-1 因为您永远不想使用 StringReader 读取狂野的 XML,除非您从外部获取编码(在 Web 服务中可能就是这种情况)。 @kdgregory - 这是因为行尾可能因编码而异吗? 我相信这是因为(愚蠢地)XML 标头可以指定字符集。但是如果你有一个字符串,你就已经有这个问题了,阅读器不会造成额外的损害。 @Tom 哈哈。所以,我认为我读入字节数组并将 BAIS 交给解析器的建议应该避免这个问题。 不,这实际上是您最不担心的问题。更糟糕的是,当您的 XML 被编码为 UTF-8(标准默认值)时,您使用 InputStreamReader 将其包装,假设它是 ISO-8859-1(美国 Linux 安装的平台默认值)或 Windows-1252(平台默认值)美国 Windows 安装)

以上是关于使用有关持久性和 XML 的 InputStream 的最佳方式的主要内容,如果未能解决你的问题,请参考以下文章

样品持久性.xml使用hibernate和mysql的

解析xml得到XmlPullParserException

xml 主要数据库和jpa提供程序的持久性xml配置

xml 主要数据库和jpa提供程序的持久性xml配置

使用XStream是实现XML与Java对象的转换--持久化

persistence.xml 中的多个持久性单元相互创建表