Шест различни "?" знаци в ASCII?

Написах програма на Arduino, която чете GameBoy колички, Java й изпраща знак за стартиране и тя започва да чете и изпраща байтове обратно. Отварянето на изхвърления rom в шестнадесетичен редактор (или дори текстов редактор) показва, че те са еднакви на пръв поглед, след използване на функцията за сравнение в редактора, той подчертава, че всички 0x3F символи в изхвърления rom са неправилни - само те. Всяка функция, която има моята програма 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 трябва да се обърква с "?" характер и винаги се приема, че това е първият случай. Пропускам ли нещо, когато прехвърлям байта [] към низ, защото изглежда, че това е очевиден проблем да го направя така, както съм.

РЕДАКТИРАНЕ 1:

Използвах asciitable.com като референция, за да накарам всички герои да бъдат еднакви.

Също така открих, че ако променя кода за писане на файл на това:

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

всички от разширения набор (128+) стават '?'. Може ли да е проблем с буферирания Writer?

Редактиране 2: Възпроизводим пример

Ето кода на Arduino и Java, който използвам.

http://pastebin.com/Tijjdb0A

След като Java е написала файла, проверете го в шестнадесетичен редактор и вижте, че символите, споменати по-горе, са променени на 0x3F.


person Lee Fogg    schedule 13.06.2014    source източник
comment
Къде отпечатвате знаците? Може би това устройство не може да отпечата тези знаци и използва ? като изход по подразбиране.   -  person Sotirios Delimanolis    schedule 13.06.2014
comment
Също така, тук има ascii и разширени ascii таблици.   -  person Sotirios Delimanolis    schedule 13.06.2014
comment
@SotiriosDelimanolis В края казах, че тези байтове всъщност са 0x3F вместо някоя от другите стойности на „?“. И аз преглеждах тази страница многократно; както показват, Java всъщност приема грешен символ.   -  person Lee Fogg    schedule 13.06.2014
comment
Можете ли да ни дадете малък възпроизводим пример? Много се съмнявам, че Java е виновен.   -  person Sotirios Delimanolis    schedule 13.06.2014
comment
@SotiriosDelimanolis Разбира се, това е, върху което работя сега - най-простото нещо.   -  person Lee Fogg    schedule 13.06.2014
comment
@SotiriosDelimanolis добави.   -  person Lee Fogg    schedule 13.06.2014


Отговори (3)


Вярвам, че проблемът е, че преобразувате необработени данни от байтове в низ и след това само записвате низа в буферирания писател. Когато се обадите на 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), всичко ще бъде наред.

person Andrey Breslav    schedule 13.06.2014
comment
Добре... Звучи ненужно сложно. Използвах FileOutoutStream и той работи (все още не съм го буферирал). Предполагам, защото приема необработени списъци с байтове. - person Lee Fogg; 15.06.2014

"всеки символ на ascii (0-255)": Най-малкото нямате представа какво е ASCII. Но не трябва да се налага; Това е остаряло. €, ..., Ÿ, ... не са ASCII.

Ако искате да третирате произволни байтове като знаци, по един байт на знак, имате нужда от набор от знаци, който има поне 256 знака и има кодиране, което използва 0-255 като еднобайтови знаци. Опитайте CP437. Java се справя добре. Вижте OutputStreamWriter.

person Tom Blodget    schedule 13.06.2014

Радвам се, че сте доволни от другите предоставени отговори. Само за да изясня погрешното схващане, породено от заглавието на въпроса:

Шест различни "?" знаци в ASCII?

Не, в ASCII няма повече от един въпросителен знак. ASCII присвоява знаци само на стойности от 0 до 127 и само един от тях (десетичен знак 63) е въпросителен знак. Има много "разширения" на ASCII, които присвояват знаци на позиции от 128 до 255, но дори и тогава някои стойности може да не са присвоени.

Петте допълнителни въпросителни знака, които виждате в резултата си, съответстват на неприсвоени позиции в Windows-1252. Windows-1252 е наборът от знаци по подразбиране в (северноамериканските издания на) Microsoft Windows, така че той влиза в действие, когато използвате класове Reader или Writer или конструктора String, без да указвате набор от знаци.

Когато Java преобразува байтове в знаци (или обратно) и срещне „поредици от неправилно въведени или несъпоставими символи“, тя използва въпросителния знак като заместващ знак. Това е намекнато в Charset Javadoc, но там не е много добре обяснено.

person gatkin    schedule 18.01.2017