【问题标题】:Accept only part of message written to ByteArrayOutputStream object仅接受写入 ByteArrayOutputStream 对象的部分消息
【发布时间】:2023-03-24 04:13:01
【问题描述】:

我正在尝试获取 SOAPMessage 对象的原始 xml,并且我正在使用 ByteArrayOutputStream 类进行此操作,但是一旦将压缩附件添加到消息对象中,它就会失去可读性。

这是我的代码:

ByteArrayOutputStream out = new ByteArrayOutputStream();
message.writeTo(out);
strMsg = new String(out.toByteArray());

其中 message 是 SOAPMessage 对象。 问题是,当我将它打印到标准输出或日志或其他一些输出时,strMsg 可能很大并且包含压缩附件的字节数据。有没有办法在将消息写入 ByteArrayOutputStream 对象时截断它?我知道,我可以轻松截断 strMsg,但我看不出有什么理由收集 ByteArrayOutputStream 中的所有数据。

【问题讨论】:

  • 如果数据被压缩,它不会任何可读性丢失,并且您没有任何业务试图将其转换为字符串。不清楚你真正要问的是什么。
  • @EJP - 我很清楚。他正在尝试捕获日志中的 SOAP 消息,而不会在有附件时用大量不可读的内容填充日志文件。
  • @StephenC 所以他需要通过SoapMessage API 获取可读的消息片段,并记录这些片段。不要将整个内容转换为ByteArrayOutputStream,然后再转换为String,这并没有开始实现该目标。
  • @EJP .... 所以写一个答案!

标签: java bytearrayoutputstream


【解决方案1】:

我知道,我可以轻松地截断 strMsg,但我没有理由收集 ByteArrayOutputStream 中的所有数据。

问题在于您只有 writeTo 方法可以使用,并且该方法旨在输出整个消息。

您可以创建ByteArrayOutputStream 的自定义变体,它只接受指定的字节数。当writeTo超过限制时,你的类需要抛出一个IO异常。

实际的问题是创建和抛出异常是昂贵的。这是“仅在例外情况下使用例外”这句口头禅的真正基础 - https://softwareengineering.stackexchange.com/questions/184654/ive-been-told-that-exceptions-should-only-be-used-in-exceptional-cases-how-do。如果您要记录大量 SOAP 消息,这可能是个问题。

异常创建/抛出的主要性能瓶颈实际上是异常对象的创建:具体是Throwable构造函数调用fillInStacktrace捕获堆栈帧的部分。有几种方法可以改善这种情况:

  • 您可以创建一个实例,将其缓存在“全局”中并多次重复使用,而不是每次new-ing 一个异常对象。

  • 如果异常是自定义异常,您可以覆盖其fillInStacktrace 方法以不执行任何操作。

在这两种情况下,如果您尝试打印堆栈跟踪,最终都会出现异常,这些异常会给您带来不正确的结果。但是,如果您使用异常来实现“非异常”代码路径(因为您别无选择!)那么这可能不相关。


上面的解决方案有一个变体,其中自定义字节接收器类默默地丢弃字节而不是抛出异常。这避免了异常的成本(但见上文),但并不能避免 writeOut 在将大型 SOAP 消息序列化到“停止侦听”的字节接收器时所做的不必要工作。


另外需要注意的是,如果您使用的是多字节字符编码(例如 UTF-8),则在一定数量的字节后截断可能会中断。考虑一下如果在 100 个字节处截断并且第 100 个字节位于字符中间会发生什么情况。请注意,如果 byte[] 包含在默认字符集中不是有效字符的序列,则未指定 new String(byte[]) 的行为。

【讨论】:

  • 为什么这个答案的五分之四是关于异常的?当您输出大量数据时,异常的微小开销(如果您得到一个)是无关紧要的。没有真正的理由为什么该类实际上应该抛出异常。但他为什么不使用writeTo(System.out),或者他为什么要尝试记录压缩数据,才是真正的问题。
  • @EJP - 这取决于抛出异常的频率以及消息大小的分布。无论如何,我以我写答案的方式写答案,因为那是 >>我
  • @EJP - “没有真正的理由让类实际上应该抛出异常。” - 实际上有。 writeTo 方法正在做很多工作(例如 XML DOM 解析)来生成序列化的字节。如果你抛出异常,那么你就省去了一堆不必要的工作。 (是的,我确实考虑过自定义 BAOS 只吃字符的替代方案。)
猜你喜欢
  • 2019-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-19
  • 1970-01-01
相关资源
最近更新 更多