I need to reassign the standard output stream to a jTextArea, which I did as follows:
我需要将标准输出流重新分配给jTextArea,如下所示:
System.setOut(new PrintStream(new StdOutput()));
class StdOutput extends OutputStream {
@Override
public void write(int b) throws IOException {
jTextArea1.append(String.valueOf((char) b));
}
}
However, I have some special characters written to the stream but they don't get displayed properly - e.g. a degree sign comes out as two chineese characters.
然而,我有一些写入流的特殊字符,但它们不能正确显示-例如,学位符号显示为两个中文字符。
I thought this may have to do with the width of the char
type and truncating the int
type to 16 bits, so not all special characters will be displayed properly. However, the degree sign is only 0x00B0
so it should fit well within a char
. What I get instead of 0x00B0
is two characters - 0xFFC2
& 0xFFB0
.
我认为这可能与char类型的宽度和将int类型截断为16位有关,因此并不是所有的特殊字符都能正确显示。但是,度数符号只有0x00B0,所以它应该正好适合一个字符。我得到的不是0x00B0,而是两个字符-0xFFC2和0xFFB0。
I also tried masking b
with 0xFFFFFFFF
and assigning different encodings to the PrintStream
instance, but had no success. What am I missing?
我还尝试用0xFFFFFFFFF屏蔽b,并为PrintStream实例分配不同的编码,但没有成功。我遗漏了什么?
更多回答
OutputStream
is for bytes, Writer
is for characters. Just writing an int
wouldn't work; it's going to output each byte as its own char rather than combining the two bytes.
OutputStream用于字节,Writer用于字符。仅仅写入int是行不通的;它将输出每个字节作为其自己的字符,而不是将两个字节组合在一起。
BTW "°".getBytes()
results in [-62, -80]
(aka [0xC2, 0xB0]
) as UTF-8 is probably the used enccoding and \u00B0
is encoded by that bytes - [Wikipedia]: "The first 128 code points (ASCII) need one byte. The next 1,920 code points need two bytes to encode, ..."
Btw“°”.getBytes()结果为[-62,-80](也称为[0xC2,0xB0]),因为UTF-8可能是使用的编码,而\u00B0是按该字节编码的-[维基百科]:“前128个码点(ASCII)需要一个字节。接下来的1,920个码点需要两个字节编码,...”
By the way, char
is physically incapable of representing most characters. Make a habit of using Unicode code point integer numbers instead: Character.toString( b )
. For DEGREE SIGN, Character.toString( 176 )
. See that code run at Ideone.com.
顺便说一句,char在物理上不能表示大多数字符。养成改用Unicode码位整数的习惯:Character.toString(B)。对于度数符号,则为Character.toString(176)。请看Ideone.com上运行的代码。
Thanks all for pointing me in the right direction, indeed I was trying to write characters using a byte stream, so any integer not fitting within the byte type was getting split. I managed to get a working solution using Charset decoder and a ByteBuffer, will post it below.
感谢所有人为我指明了正确的方向,事实上,我正在尝试使用字节流写入字符,因此任何不适合字节类型的整数都会被拆分。我设法得到了一个使用字符集解码器和ByteBuffer的有效解决方案,我将在下面发布它。
优秀答案推荐
I think you must specify the character encoding when creating the PrintStream
, because when you append the value of (char) b
to the jTextArea1
, it assumes the default character encoding of your system and not be able to display certain characters properly!
我认为您必须在创建PrintStream时指定字符编码,因为当您将(Char)b的值附加到jTextArea1后,它将采用系统的默认字符编码,并且无法正确显示某些字符!
For the PrintStream
constructor, pass the parameter for Charset
, such as StandardCharsets.UTF_8
.
对于PrintStream构造函数,传递Charset的参数,如StandardCharsets.UTF_8。
System.setOut(new PrintStream(new StdOutput(), true, StandardCharsets.UTF_8));
class StdOutput extends OutputStream {
@Override
public void write(int b) throws IOException {
jTextArea1.append(String.valueOf((char) b));
}
}
Thanks to the people who commented on my original post, I came up with something that works for my situation:
感谢评论我最初帖子的人,我想出了一些适合我的情况的东西:
bb = ByteBuffer.allocateDirect(500);
cs = Charset.forName("UTF-8");
dc = cs.newDecoder();
System.setOut(new PrintStream(new StdOutput(), true));
class StdOutput extends OutputStream {
@Override
public void write(int b) throws IOException {
if (b == '\n') {
bb.put((byte)'\n');
bb.rewind();
jTextArea1.append(dc.decode(bb).toString());
bb = ByteBuffer.allocateDirect(500);
} else {
bb.put((byte) b);
}
}
}
Obviously that is pretty clumsy and only works for my locale and if I put a single string of a known length per write call, so if anyone can suggest a more elegant solution for writing characters to the standard output stream - I would highly appreciate it!
显然,这非常笨拙,而且只适用于我的区域设置,如果我在每次WRITE调用中放置一个已知长度的单个字符串,那么如果有人可以建议一个更优雅的解决方案来将字符写入标准输出流-我将非常感激!
更多回答
Thanks, that was one of the first things I tried but it did not work. The problem here is that the byte stream is still being used to write int-long characters per every write(int b) call.
谢谢,这是我第一次尝试的方法之一,但没有奏效。这里的问题是,字节流仍然被用来在每个WRITE(Int B)调用中写入整型字符。
What was your particular motivation for remapping System.out
?
您重新映射System.out的具体动机是什么?
@g00se I have a large TextArea where the app displays status codes and other messages while it runs, so I thought redirecting the standard output to it would make it more convinient for diagnostic purposes e.g. exceptions display, use of System.out.print() in the code etc. Looking purely at the overhead it added and other issues I faced I would not use it in production code. Was still worth the effort to see if it was possible at all and learn something new.
@g00se我有一个很大的TextArea,应用程序在运行时会显示状态代码和其他消息,所以我认为将标准输出重定向到它会使它更方便用于诊断目的,例如异常显示,在代码中使用System.out.print()等。仍然值得努力看看是否有可能并学习新的东西。
我是一名优秀的程序员,十分优秀!