【问题标题】:Convert ASCII byte[] to String将 ASCII 字节 [] 转换为字符串
【发布时间】:2011-01-13 04:50:51
【问题描述】:

我正在尝试将包含 ASCII 字符的 byte[] 传递给 log4j,以使用明显的表示形式登录到文件中。当我简单地传入 byt[] 时,它当然被视为一个对象,并且日志毫无用处。当我尝试使用new String(byte[] data) 将它们转换为字符串时,我的应用程序的性能减半。

我怎样才能有效地将它们传递进去,而不会产生将它们转换为字符串的大约 30us 时间损失。

另外,为什么转换它们需要这么长时间?

谢谢。

编辑

我应该补充一点,我在这里优化延迟 - 是的,30us 确实有所作为!此外,这些数组从 ~100 一直到几千字节不等。

【问题讨论】:

    标签: java log4j ascii bytearray


    【解决方案1】:

    ASCII 是少数无需算术或查表即可与 UTF16 相互转换的编码之一,因此可以手动转换:

    String convert(byte[] data) {
        StringBuilder sb = new StringBuilder(data.length);
        for (int i = 0; i < data.length; ++ i) {
            if (data[i] < 0) throw new IllegalArgumentException();
            sb.append((char) data[i]);
        }
        return sb.toString();
    }
    

    但要确保它真的是 ASCII,否则你会得到垃圾。

    【讨论】:

    • 这段代码对我有用。但是 new String(byteArray) 让我的 Android 应用程序崩溃了。你能解释一下区别吗?
    【解决方案2】:

    您想要做的是延迟 byte[] 数组的处理,直到 log4j 决定它实际上想要记录消息。这样,您可以在调试级别记录它,例如,在测试时,然后在生产期间禁用它。例如,您可以:

    final byte[] myArray = ...;
    Logger.getLogger(MyClass.class).debug(new Object() {
        @Override public String toString() {
            return new String(myArray);
        }
    });
    

    现在,除非您实际记录数据,否则您无需支付速度损失,因为在 log4j 决定它将实际记录消息之前不会调用 toString 方法!

    现在我不确定您所说的“明显表示”是什么意思,所以我假设您的意思是通过将字节重新解释为默认字符编码来转换为字符串。现在,如果您正在处理二进制数据,这显然毫无价值。在这种情况下,我建议使用Arrays.toString(byte[]) 来创建一个格式化字符串,类似于

    [54, 23, 65, ...]
    

    【讨论】:

    • 很好,使用异步记录器可以使转换远离关键路径。
    【解决方案3】:

    如果您的数据实际上是 ASCII(即 7 位数据),那么您应该使用 new String(data, "US-ASCII") 而不是依赖于平台默认编码。这可能比尝试将其解释为您的平台默认编码(可能是 UTF-8,这需要更多内省)更快。

    您还可以通过缓存Charset 实例并改为调用new String(data, charset) 来避免每次都命中字符集查找来加快速度。

    话虽如此:我已经很长时间没有在生产环境中看到真正的 ASCII 数据了

    【讨论】:

    • 这和finnw的回答有什么区别?
    • 取决于您所处的生产环境,先生。我每天都看到它。
    【解决方案4】:

    性能减半?这个字节数组有多大?例如,如果它是 1MB,那么肯定有更多的因素需要考虑,而不仅仅是从字节“转换”为字符(尽管这应该足够快)。 写入 1MB 数据而不是“仅” 100 字节(byte[].toString() 可能会生成)写入日志文件显然需要一些时间。磁盘文件系统不如 RAM 内存快。

    您需要更改字节数组的字符串表示形式。也许有一些更敏感的信息,例如与它相关的名称(文件名?),它的长度等等。毕竟,那个字节数组究竟代表什么?

    编辑:我不记得在您的问题中看到过“大约 30us” 短语,也许您在询问后 5 分钟内对其进行了编辑,但这实际上是微优化,通常它肯定不会导致“性能减半”。除非你每秒写一百万次(到那时,你为什么要这样做?你不是过度使用“记录”现象吗?)。

    【讨论】:

    • 这些数组变化很大,从大约 150 字节一直到 4000 字节。回覆。您的最后一点,我正在优化延迟而不是吞吐量 - 所以我要么需要将此转换远离关键路径,要么加快它...
    • 另外,遗憾的是,需要记录所有这些数据 - 是的,这是很多数据......
    • 那么你的瓶颈更多是在磁盘 IO 中而不是在 Java 代码中——正如我所料。
    【解决方案5】:
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-17
    • 2013-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多