我写了一个读取GameBoy推车的Arduino程序,Java发送一个字符开始,它开始读取并发回字节。在十六进制编辑器(甚至文本编辑器)中打开转储的rom,乍一看显示它们是相同的,在编辑器中使用compare函数后,它突出显示转储rom中的所有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必须与&#39;?&#39;混淆。角色,并始终假设它是第一个实例。在将byte []转换为字符串时,我是否遗漏了一些东西,因为看起来这是一个明显的问题,就像我一样。
编辑1:
我一直在使用asciitable.com作为让所有角色都一致的依据。
我还发现,如果我将文件编写代码更改为:
byte[] data = board.read(readsize);
for (byte in : data)
rom.write(in);
所有扩展集(128+)都变成了&#39;?&#39; s。这可能是bufferedWriter的一个问题吗?
编辑2:可重复的示例
这是我正在使用的Arduino和Java代码。
在Java编写文件后,在十六进制编辑器中检查它,并看到上面提到的字符都已更改为0x3F。
答案 0 :(得分:0)
我认为问题在于您将原始数据从字节转换为String,然后只将字符串写入缓冲的writer。根据文档
,当您致电new String(byte[])
时
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)
,一切都会好的。
答案 1 :(得分:0)
“每个ascii字符(0-255)”:至少你不了解ASCII是什么。但你不应该这样做;它已经过时了。 €,...,Ÿ,...不是ASCII。
如果要将任意字节视为字符,每个字符一个字节,则需要一个至少包含256个字符的字符集,并且编码使用0-255作为单字节字符。试试CP437。 Java处理得很好。请看OutputStreamWriter。
答案 2 :(得分:0)
我很高兴你对提供的其他答案感到满意。只是为了澄清问题标题所带来的误解:
六种不同'?' ASCII中的字符?
不,ASCII中的问号不超过一个。 ASCII仅将字符分配给值0到127,并且只有其中一个(十进制63)是问号。 ASCII有许多“扩展”,它们将字符分配给位置为128到255的位置,但即使这样,某些值也可能未被分配。
您在输出中看到的五个额外问号对应于Windows-1252中的未分配位置。 Windows-1252是Microsoft Windows的(北美版)中的默认字符集,因此当您使用Reader或Writer类或String构造函数时,它会发挥作用,而不指定字符集。
当Java将字节转换为字符(反之亦然)并遇到“格式错误的输入或不可映射的字符序列”时,它会使用问号作为替换字符。这在Charset Javadoc中暗示过,但在那里没有得到很好的解释。