【问题标题】:Convert a byte array from Encoding A to Encoding B将字节数组从编码 A 转换为编码 B
【发布时间】:2016-03-28 14:09:41
【问题描述】:

我有一个非常有趣的话题——至少对我来说是这样。给定一个带有字节的 ByteArrayOutputStream,例如 UTF-8 中的字节,我需要一个可以将这些字节“翻译”成另一个 - 新的 - ByteArrayOutputStream 的函数,例如 UTF-16 或 ASCII 或你的名字。我幼稚的方法是使用 InputStreamReader 并提供所需的编码,但这不起作用,因为它会读入 char[] 而我只能将 byte[] 写入新的 BAOS。

public byte[] convertStream(Charset encoding) {
    ByteArrayInputStream original = new ByteArrayInputStream(raw.toByteArray());
    InputStreamReader contentReader = new InputStreamReader(original, encoding);
    ByteArrayOutputStream converted = new ByteArrayOutputStream();

    int readCount;
    char[] buffer = new char[4096];
    while ((readCount = contentReader.read(buffer, 0, buffer.length)) != -1)
        converted.write(buffer, 0, readCount);

    return converted.toByteArray();
}

现在,这显然行不通,我正在寻找一种方法来使这种情况成为可能,而无需从 byte[] 构建字符串。

@编辑: 因为阅读明显的东西似乎相当困难。 1) raw: ByteArrayOutputStream 包含从客户端发送给我们的 BINARY 对象的字节。这些字节通常以 UTF-8 作为 HTTP 消息的一部分。 2)这里的目标是将此 BINARY 数据转发到不灵活的内部系统 - 这是一个内部系统 - 它接受 UTF-16 中的此类附件。我不知道为什么甚至不问,它确实这样做了。

所以为了证明我的问题是正确的:有没有办法将字节数组从 Charset A 转换为 Charset B 或您选择的编码。再次构建字符串不是我所追求的。

谢谢你,希望能解决有问题的部分:)。

【问题讨论】:

  • 什么是raw?你只给了我们部分信息。我希望只是将字节转换为字符串,然后再从字符串转换回字节数组。根本不需要使用流。
  • 好吧,raw 显然是一个 ByteArrayOutputStream,其中包含我们的客户端对二进制数据使用的任何编码的字节。我们必须以 utf-8 格式将此数据传输到我们的系统,因此我们需要将任何内容转换为 utf-8 或其他任何内容。我希望这能清除它。建立一个字符串现在是没有问题的。
  • 为什么构建一个字符串是不可能的?如果最明显的方法不合适,您需要解释为什么会出现这种情况。一个简短但完整的示例的好处是,您认为“显而易见”的内容已在代码中说明。我经常做出对我来说似乎“显而易见”的假设,但事实证明并非如此......当你现在对什么是可行的和什么不可行添加限制时,这会增加混乱。
  • 但是建立一个字符串的答案确实回答了你原来的问题。原始问题中没有任何内容可以解释您为什么不想这样做。你还没有说为什么你拒绝创建一个字符串。对试图帮助你的人无礼是一个非常非常糟糕的主意。

标签: java encoding


【解决方案1】:

如 cmets 中所述,我只是转换为字符串:

String text = new String(raw.toByteArray(), encoding);
byte[] utf8 = text.getBytes(StandardCharsets.UTF_8);

但是,如果这不可行(出于某种未指明的原因...),您现在所拥有的就差不多了 - 您只需在组合中添加一个 OutputStreamWriter

// Nothing here should throw IOException in reality - work out what you want to do.
public byte[] convertStream(Charset encoding) throws IOException {       
    ByteArrayInputStream original = new ByteArrayInputStream(raw.toByteArray());
    InputStreamReader contentReader = new InputStreamReader(original, encoding);

    int readCount;
    char[] buffer = new char[4096];
    try (ByteArrayOutputStream converted = new ByteArrayOutputStream()) {
        try (Writer writer = new OutputStreamWriter(converted, StandardCharsets.UTF_8)) {
            while ((readCount = contentReader.read(buffer, 0, buffer.length)) != -1) {
                writer.write(buffer, 0, readCount);
            }
        }
        return converted.toByteArray();
    }
}

请注意,您仍在内存中创建数据的额外临时副本,诚然是使用 UTF-8 而不是 UTF-16...但从根本上说,这几乎不比创建字符串更有效。

如果内存效率是一个特别关注的问题,您可以执行多次传递以确定需要多少字节,创建一个写入长度的字节数组,然后将代码调整为直接写入该字节数组。

【讨论】:

  • 完美的 OutputStreamWriter 就是答案!这对我来说已经足够了!
猜你喜欢
  • 2015-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-25
  • 2021-12-18
  • 1970-01-01
  • 2020-10-26
  • 2011-11-03
相关资源
最近更新 更多