Шесть разных '?' символы в 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+) становится '?'s. Может ли это быть проблемой с bufferedWriter?

Изменить 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 преобразует байты в символы (или наоборот) и сталкивается с «неверно сформированными входными или неотображаемыми последовательностями символов», он использует вопросительный знак в качестве заменяющего символа. На это намекает кодировка Javadoc, но там не очень хорошо объяснено.

person gatkin    schedule 18.01.2017