Проблема байт Java в строковое кодирование в Linux - PullRequest
1 голос
/ 11 августа 2011

Я реализую часть программного обеспечения, которая работает следующим образом:

У меня есть сервер Linux, на котором запущено приложение терминала vt100, которое выводит текст. Моя программа соединяется с сервером по сети и считывает / анализирует биты текста в соответствующих данных. Соответствующие данные отправляются небольшому клиенту, запущенному веб-сервером, который выводит данные на HTML-страницу.

Моя проблема в том, что определенные специальные символы, такие как "åäö", выводятся в виде вопросительных знаков (классика).

Справочная информация:
Моя программа читает поток байтов, используя Apache Commons TelnetClient . Поток байтов преобразуется в строку, затем соответствующие биты подстрокуются и возвращаются вместе с символами-разделителями. После этого новая строка преобразуется обратно в байтовый массив и отправляется с помощью сокета клиенту, запущенному веб-сервером. Этот клиент создает строку из полученных байтов и выводит ее на стандартный вывод, который веб-сервер считывает и выводит HTML.

Шаг 1: byte [] -> String -> byte [] -> [отправить клиенту]

Шаг2: byte [] -> String -> [print output]

Проблема:
Когда я запускаю свою программу на Java в Windows, все символы, включая «åäö», правильно выводятся на итоговую HTML-страницу. Однако, если я запускаю программу в Linux , все специальные символы преобразуются в "? " (вопросительный знак).

Веб-сервер и клиент в настоящее время работают в Windows (шаг 2).

Код:
Программа в основном работает так:

Моя программа:

byte[] data = telnetClient.readData() // Assume method works and returns a byte[] array of text.

// I have my reasons to append the characters one at a time using a StringBuffer.
StringBuffer buf = new StringBuffer();
for (byte b : data) {
    buf.append((char) (b & 0xFF));
}

String text = buf.toString();

// ...
// Relevant bits are substring'ed and put back into the String.
// ...

ServerSocket serverSocket = new ServerSocket(...);
Socket socket = serverSocket.accept();
serverSocket.close();

socket.getOutputStream.write(text.getBytes());
socket.getOutputStream.flush();

Клиент, запущенный веб-сервером:

Socket socket = new Socket(...);

byte[] data = readData(socket); // Assume this reads the bytes correctly.

String output = new String(data);

System.out.println(output);

Предположим, синхронизация между чтением и записью работает.

Мысли:
Я пробовал с различными способами кодирования и декодирования байтового массива без результатов. Я немного новичок в вопросах кодирования кодировки и хотел бы получить несколько советов. Кодировка по умолчанию в Windows «WINDOWS 1252», по-видимому, пропускает специальные символы через весь сервер к веб-серверу, но при запуске на компьютере с Linux кодировка по умолчанию отличается. Я попытался запустить Charset.defaultCharset (). ForName (), и он показывает, что мой компьютер с Linux установлен на «US-ASCII». Я думал, что Linux по умолчанию "UTF-8"?

Как мне сделать, чтобы моя программа работала в Linux?

Ответы [ 3 ]

8 голосов
/ 11 августа 2011

Обычно плохая идея полагаться на кодировку платформы по умолчанию, особенно для сетевого протокола связи.

И new String(), и String.getBytes() перегружены, чтобы вы могли указать кодировку. Поскольку вы управляете кодированием и декодированием, просто используйте UTF-8 (жестко закодированный).

Также проверьте ваш код на предмет использования FileInputStream, FileOutputStream, InputStreamReader и OutputStreamWriter, все из которых в основном полагаются на кодировку по умолчанию платформы (первые два, исключительно, что делает их довольно бесполезными).

3 голосов
/ 11 августа 2011

String(byte[] bytes, String encoding) твой друг.Просто прочитайте все необработанные байты в байтовый буфер и используйте этот конструктор для декодирования байтов в строку Java.(или: перекодировать в UTF-16, внутренняя кодировка символов)

Метод getBytes(String encoding) будет кодировать строку в байтах.

0 голосов
/ 11 августа 2011

Ключевым моментом является то, какова кодировка данных, возвращаемых из telnetClient.readData()?Похоже, что это windows-1252.Имея это в виду, у вас есть несколько вариантов.Вы можете явно установить кодировку для всех операций String на windows-1252:

text.getBytes("windows-1252");

String output = new String(data, "windows-1252");

Или вы можете использовать java.nio.charset.Charset для преобразования данных telnet во что-то менее специфичное для платформы, например UTF-8этот пример: Преобразование UTF-8 в ISO-8859-1 в Java - как сохранить его как один байт - тем не менее, при этом все же устанавливается набор символов в операциях String явно.

...