Java InputStream для чтения зависит от локали? - PullRequest
0 голосов
/ 28 января 2019

У меня клиент-серверное приложение.Клиент (приложение C ++) отправляет строку в кодировке UTF8, а сервер (приложение Java) читает эти строки через соединение через сокет-порт.У меня возникают проблемы при чтении строки на стороне сервера в случае, если сервер размещен в ОС Windows с языковым стандартом CP-1252.

Вот псевдокод

private transient Socket socket = null;
private transient InputStream in = null;
private transient OutputStream out = null;

socket = new Socket(server, port);
out = socket.getOutputStream();
in = socket.getInputStream();

Socket и InputStreamинициализируется в некоторой другой функции, и фактическая строка читается, как показано в функции ниже:

ReadString()
{
    byte[] backbytes = new byte[2048];

    {
        if ((c = in.read(backbytes)) > 0) {
            if (debug)
                logger.trace("Read " + c + " bytes");
            total = total + c;
            char[] convertedChar = new char[backbytes.length];
            int[] convertedInt = new int[backbytes.length];
            for(int i=0;i < backbytes.length;i++){
                convertedChar[i] = (char) backbytes[i];
                convertedInt[i] = (int) backbytes[i];
            }

            logFilePrint.print("Read string as : " + new String(backbytes, 0, c) + " and the converted char[] of byte[] is : ");
            printArray(logFilePrint, convertedChar);
            logFilePrint.print(" and converted int[] is : " );
            printArray(logFilePrint, convertedInt);
            logFilePrint.flush();

            sb.append(new String(backbytes, 0, c));
        } else {
          break;
        }
    }
}

Проблема возникает для определенных символов Unicode, таких как «私» или «の».Если я выполню приведенный выше код для этих символов, я получу вывод как

Считать строку как: ç§? Ã?и преобразованный символ [] байта []: [, ￧, ᄃ,?,  ̄,?,] и преобразованный int []: [, -25, -89, 63, -29, 63, -82,]

Однако, если я изменяю кодировку сервера, устанавливая кодировку JVM в UTF8, используя "-Dfile.encoding = UTF-8", я получаю вывод в виде:

Чтение строкиas: の の и преобразованный символ [] байта []: [, ￧, ᄃ, チ,  ̄, チ, ᆴ] и преобразованный int []: [, -25, -89, -127, -29, -127, -82,]

Проблема в режиме, отличном от UTF8, связана с символами с байтом '0x81'.Например, символ '私' имеет кодировку UTF-8 '0xE7 0xA7 0x81', а 'の' имеет кодировку UTF-8 '0xE3 0x81 0xAE'

Насколько я понимаю, InputStream "in.read (backbytes)"просто читает байты отправленных данных.Почему должны быть затронуты считываемые байты в случае, если кодировка JVM является UTF-8 и не UTF8?Зависит ли локаль от функции чтения?

1 Ответ

0 голосов
/ 28 января 2019

Выбранный вами конструктор, String(byte[] encoded, int offset, int length), использует кодировку платформы по умолчанию для преобразования байтов в символы.Это явно зависит от среды, в которой он работает.

Это плохой выбор для переносимого кода.Для сетевых приложений явно укажите кодировку, которая будет использоваться.Вы можете согласовать это как часть сетевого протокола или указать полезное значение по умолчанию, например UTF-8.

Существует множество API, которые кодируют и декодируют текст.Например, конструктор String String(byte[] encoded, int offset, int length, Charset encoding) можно использовать так:

String str = new String(backbytes, 0, c, StandardCharsets.UTF_8);
...