ASCII 中有六个不同的"?"字符?



我写了一个Arduino程序,读取GameBoy推车,Java发送它一个字符开始,它开始读取和发送字节返回。在十六进制编辑器(甚至是文本编辑器)中打开转储的空间,乍一看它们是相同的,在使用编辑器中的比较函数后,它突出显示转储空间中的所有0x3F字符都是不正确的-只有它们。在此之前,我的Arduino程序的每个功能都经过了测试,所以我唯一能想到的就是测试Java端。为了测试这一点,我简单地编写了另一个简单的Arduino程序,它通过串行发送十进制数旁边的每个ascii字符(0-255)。我意识到实际上有六种不同的?字符,这里是文件的这些部分:

59: ;
60: <
61: =
62: >
63: ? <
64: @
65: A
66: B
...
125: }
126: ~
127: 
128: €
129: ? <
130: ‚
131: ƒ
132: „
...
140: Œ
141: ? <
142: Ž
143: ? <
144: ? <
145: ‘
146: ’
147: “
...
154: š
155: ›
156: œ
157: ? <
158: ž
159: Ÿ
160:  

下面是有问题的Java代码:

final Arduino board = new Arduino("COM5", 115200);
BufferedWriter rom = new BufferedWriter(new FileWriter("[ROM].gb"));
board.write((byte)0);
Thread.sleep(10000);
while (board.hasavailable() > 0) {
    String data = new String(board.read(board.hasavailable()));
    rom.write(data);
    Thread.sleep(1000);
}
rom.flush();
rom.close();

我看不出这是一个通信问题,如果波特率是错误的,那将是垃圾,当然,如果这是一个文本格式问题,如UTF-8到ASCII…基本上Java肯定会和'?’的性格,总是假设这是第一次。当将byte[]转换为字符串时,我是否错过了一些东西,因为这似乎是我这样做的一个明显的问题。

编辑1:

我一直使用asciitable.com作为参考,以获得所有字符相同。

我还发现,如果我将文件写入代码更改为:

byte[] data = board.read(readsize);
for (byte in : data)
    rom.write(in);

所有扩展集(128+)都变成'?'。这可能是bufferedWriter的问题吗?

编辑2:可复制示例

这是我使用的Arduino和Java代码。

http://pastebin.com/Tijjdb0A

Java编写完文件后,在十六进制编辑器中检查一下,看看上面提到的字符是否都被更改为0x3F。

我认为问题是您正在将原始数据从字节转换为字符串,然后仅将字符串写入缓冲写入器。当你调用new String(byte[])时,根据docs

Constructs a new String by decoding the specified array of bytes using the platform's default charset.

这意味着它接受您的字节,假设它是您机器上的任何默认字符集的字符串,然后将其转换为UTF-16,这是Java中字符串的内部表示形式。在许多平台上,"默认字符集"意味着UTF-8,而在UTF-8中,"扩展ASCII"的大多数字节,即128或更高,都是较长字符的一部分,占用超过一个字节。您的字节可能不是一个有效的UTF-8字符串,所以一些字符被损坏。

我想如果你直接写字节到你的文件,而不是先做一个字符串,即使用BufferedOutputStream(FileOutputStream),而不是BufferedWriter(FileWriter),一切都会好的

"每个ASCII字符(0-255)"至少你不知道ASCII是什么。但你不需要这么做;这是过时了。€,……, Ÿ,…都不是ASCII码。

如果您想将任意字节视为字符,每个字符一个字节,则需要一个至少包含256个字符的字符集,并且具有使用0-255作为单字节字符的编码。CP437试试。Java很好地处理了这个问题。查看OutputStreamWriter

我很高兴您对提供的其他答案感到满意。为了澄清问题标题造成的误解:

六个不同的'?ASCII字符?

不,ASCII中只有一个问号。ASCII只将字符分配给0到127的值,其中只有一个(十进制63)是问号。有许多ASCII的"扩展"将字符分配到128到255的位置,但即使这样,一些值也可能被取消分配。

您在输出中看到的五个额外问号对应于Windows-1252中未分配的位置。Windows-1252是Microsoft Windows(北美版本)中的默认字符集,因此当您使用Reader或Writer类或String构造函数而不指定字符集时,它就会发挥作用。

当Java将字节转换为字符(反之亦然)并遇到"格式错误的输入或不可映射的字符序列"时,它使用问号作为替换字符。这在Charset Javadoc中有暗示,但没有很好地解释。

最新更新