Java 中的 ByteBuffer 和 String 之间的转换问题
Problems Converting Between ByteBuffer and String in Java
我目前正在开发一个应用程序,用户可以在其中通过十六进制编辑器界面编辑 ByteBuffer,还可以通过 JTextPane 编辑相应的文本。我当前的问题是因为 JTextPane 需要一个字符串,我需要在显示值之前将 ByteBuffer 转换为字符串。但是,在转换过程中,无效字符将替换为字符集默认替换字符。这会压缩无效值,因此当我将其转换回字节缓冲区时,无效字符值将替换为默认替换字符的字节值。有没有一种简单的方法可以保留字符串中无效字符的字节值?我已阅读以下 Whosebug 帖子,但通常人们只想替换不可打印的字符,我需要保留它们。
Java ByteBuffer to String
Java: Converting String to and from ByteBuffer and associated problems
有没有一种简单的方法可以做到这一点,或者我是否需要跟踪文本编辑器中发生的所有更改并将它们应用到 ByteBuffer?
这是演示问题的代码。代码使用 byte[] 而不是 ByteBuffer 但问题是一样的。
byte[] temp = new byte[16];
// 0x99 isn't a valid UTF-8 Character
Arrays.fill(temp,(byte)0x99);
System.out.println(Arrays.toString(temp));
// Prints [-103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103]
// -103 == 0x99
System.out.println(new String(temp));
// Prints ����������������
// � is the default char replacement string
// This takes the byte[], converts it to a string, converts it back to a byte[]
System.out.println(Arrays.toString(new String(temp).getBytes()));
// I need this to print [-103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103]
// However, it prints
//[-17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67]
// The printed byte is the byte representation of �
您认为 new String(temp).getBytes()
对您有什么帮助?
我可以告诉你它做了一些坏事。
- 它使用默认编码将
temp
转换为 String
,这可能是错误的,并且可能会丢失信息。
- 它使用默认编码将结果转换回字节数组。
要将 byte[]
转换为 String
,您必须始终将 Charset
传递给 String
构造函数,否则直接使用解码器。由于您使用的是缓冲区,因此您可能会发现解码器 API 很合适。
要将 String
转换为 byte[]
,您必须始终调用 getBytes(Charset)
以便您知道您使用的是正确的字符集。
根据评论,我现在怀疑您的问题是您需要编写类似下面的代码来将 UI 从字节转换为十六进制。 (然后相应的东西回来。)
String getHexString(byte[] bytes) {
StringBuilder builder = new StringBuilder();
for (byte b : bytes) {
int nibble = b >> 4;
builder.append('0' + nibble);
nibble = b & 0xff;
builder.append('0' + nibble);
}
return builder.toString();
}
特别是UTF-8会出错
byte[] bytes = {'a', (byte) 0xfd, 'b', (byte) 0xe5, 'c'};
String s = new String(bytes, StandardCharsets.UTF_8);
System.out.println("s: " + s);
需要一个 CharsetDecoder。可以忽略(=删除)或替换有问题的字节,或者默认情况下:抛出异常。
对于 JTextPane,我们使用 HTML,因此我们可以在 <span>
中写入有问题的字节的十六进制代码,给它一个红色背景。
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
CharBuffer charBuffer = CharBuffer.allocate(bytes.length * 50);
charBuffer.append("<html>");
for (;;) {
try {
CoderResult result = decoder.decode(byteBuffer, charBuffer, false);
if (!result.isError()) {
break;
}
} catch (RuntimeException ex) {
}
int b = 0xFF & byteBuffer.get();
charBuffer.append(String.format(
"<span style='background-color:red; font-weight:bold'> %02X </span>",
b));
decoder.reset();
}
charBuffer.rewind();
String t = charBuffer.toString();
System.out.println("t: " + t);
代码反映的不是很好API,不过玩玩吧。
我目前正在开发一个应用程序,用户可以在其中通过十六进制编辑器界面编辑 ByteBuffer,还可以通过 JTextPane 编辑相应的文本。我当前的问题是因为 JTextPane 需要一个字符串,我需要在显示值之前将 ByteBuffer 转换为字符串。但是,在转换过程中,无效字符将替换为字符集默认替换字符。这会压缩无效值,因此当我将其转换回字节缓冲区时,无效字符值将替换为默认替换字符的字节值。有没有一种简单的方法可以保留字符串中无效字符的字节值?我已阅读以下 Whosebug 帖子,但通常人们只想替换不可打印的字符,我需要保留它们。
Java ByteBuffer to String
Java: Converting String to and from ByteBuffer and associated problems
有没有一种简单的方法可以做到这一点,或者我是否需要跟踪文本编辑器中发生的所有更改并将它们应用到 ByteBuffer?
这是演示问题的代码。代码使用 byte[] 而不是 ByteBuffer 但问题是一样的。
byte[] temp = new byte[16];
// 0x99 isn't a valid UTF-8 Character
Arrays.fill(temp,(byte)0x99);
System.out.println(Arrays.toString(temp));
// Prints [-103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103]
// -103 == 0x99
System.out.println(new String(temp));
// Prints ����������������
// � is the default char replacement string
// This takes the byte[], converts it to a string, converts it back to a byte[]
System.out.println(Arrays.toString(new String(temp).getBytes()));
// I need this to print [-103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103]
// However, it prints
//[-17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67]
// The printed byte is the byte representation of �
您认为 new String(temp).getBytes()
对您有什么帮助?
我可以告诉你它做了一些坏事。
- 它使用默认编码将
temp
转换为String
,这可能是错误的,并且可能会丢失信息。 - 它使用默认编码将结果转换回字节数组。
要将 byte[]
转换为 String
,您必须始终将 Charset
传递给 String
构造函数,否则直接使用解码器。由于您使用的是缓冲区,因此您可能会发现解码器 API 很合适。
要将 String
转换为 byte[]
,您必须始终调用 getBytes(Charset)
以便您知道您使用的是正确的字符集。
根据评论,我现在怀疑您的问题是您需要编写类似下面的代码来将 UI 从字节转换为十六进制。 (然后相应的东西回来。)
String getHexString(byte[] bytes) {
StringBuilder builder = new StringBuilder();
for (byte b : bytes) {
int nibble = b >> 4;
builder.append('0' + nibble);
nibble = b & 0xff;
builder.append('0' + nibble);
}
return builder.toString();
}
特别是UTF-8会出错
byte[] bytes = {'a', (byte) 0xfd, 'b', (byte) 0xe5, 'c'};
String s = new String(bytes, StandardCharsets.UTF_8);
System.out.println("s: " + s);
需要一个 CharsetDecoder。可以忽略(=删除)或替换有问题的字节,或者默认情况下:抛出异常。
对于 JTextPane,我们使用 HTML,因此我们可以在 <span>
中写入有问题的字节的十六进制代码,给它一个红色背景。
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
CharBuffer charBuffer = CharBuffer.allocate(bytes.length * 50);
charBuffer.append("<html>");
for (;;) {
try {
CoderResult result = decoder.decode(byteBuffer, charBuffer, false);
if (!result.isError()) {
break;
}
} catch (RuntimeException ex) {
}
int b = 0xFF & byteBuffer.get();
charBuffer.append(String.format(
"<span style='background-color:red; font-weight:bold'> %02X </span>",
b));
decoder.reset();
}
charBuffer.rewind();
String t = charBuffer.toString();
System.out.println("t: " + t);
代码反映的不是很好API,不过玩玩吧。