Подтвердить что ты не робот

Преобразовать ASCII-байт [] в строку

Я пытаюсь передать байт [], содержащий символы ASCII, в log4j, чтобы войти в файл, используя очевидное представление. Когда я просто передаю байты [], это, конечно, рассматривается как объект, и журналы довольно бесполезны. Когда я пытаюсь преобразовать их в строки с помощью new String(byte[] data), производительность моего приложения уменьшается вдвое.

Как я могу эффективно передавать их, не прибегая к штрафу в 30 секунд для преобразования их в строки.

Кроме того, почему так долго нужно их преобразовывать?

Спасибо.

Edit

Я должен добавить, что здесь я предпочитаю латентность - и да, 30us действительно имеет значение! Кроме того, эти массивы варьируются от ~ 100 до нескольких тысяч байт.

4b9b3361

Ответ 1

Что вы хотите сделать, так это отложить обработку массива byte [] до тех пор, пока log4j не решит, что он действительно хочет записать сообщение. Таким образом, вы можете зарегистрировать его на уровне DEBUG, например, во время тестирования, а затем отключите его во время производства. Например, вы можете:

final byte[] myArray = ...;
Logger.getLogger(MyClass.class).debug(new Object() {
    @Override public String toString() {
        return new String(myArray);
    }
});

Теперь вы не платите штраф за скорость, за исключением случаев, когда вы действительно регистрируете данные, потому что метод toString не вызывается до тех пор, пока log4j не решит, что он действительно зарегистрирует сообщение!

Теперь я не уверен, что вы подразумеваете под "очевидным представлением", поэтому я предположил, что вы имеете в виду преобразование в String путем переинтерпретации байтов в качестве кодировки по умолчанию. Теперь, если вы имеете дело с двоичными данными, это, безусловно, бесполезно. В этом случае я бы предложил использовать Arrays.toString(byte []) для создания форматированной строки вдоль строк

[54, 23, 65, ...]

Ответ 2

ASCII - одно из немногих кодировок, которые могут быть преобразованы в/из UTF16 без арифметических или табличных запросов, поэтому можно преобразовать вручную:

String convert(byte[] data) {
    StringBuilder sb = new StringBuilder(data.length);
    for (int i = 0; i < data.length; ++ i) {
        if (data[i] < 0) throw new IllegalArgumentException();
        sb.append((char) data[i]);
    }
    return sb.toString();
}

Но убедитесь, что это действительно ASCII, или вы получите мусор.

Ответ 3

Если ваши данные на самом деле ASCII (т.е. 7-битные данные), то вы должны использовать new String(data, "US-ASCII") вместо зависимости от кодировки по умолчанию платформы. Это может быть быстрее, чем пытаться интерпретировать его как кодировку по умолчанию для платформы (что может быть UTF-8, что требует большей интроспекции).

Вы также можете ускорить это, избегая каждый раз Charset-Lookup, кэшируя экземпляр Charset и вызывающий new String(data, charset).

Сказав это: это было очень, очень долгое время с тех пор, как я увидел реальные данные ASCII в производственной среде

Ответ 5

Снижение производительности? Насколько велик массив байтов? Если это, например, 1MB, то, конечно, есть больше факторов, которые нужно учитывать, чем просто "конвертирование" из байт в символы (который должен быть достаточно быстрым, хотя). Написание 1 МБ данных вместо "всего" 100 байтов (которые может генерировать byte[].toString()) в файл журнала, очевидно, потребуется некоторое время. Файловая система диска не так быстро, как оперативная память.

Вам нужно будет изменить строковое представление массива байтов. Может быть, с некоторой более чувствительной информацией, например. имя, связанное с ним (имя файла?), его длину и т.д. В конце концов, что представляет собой массив байтов?

Изменить. Я не помню, чтобы вы видели фразу "приблизительно 30us" в своем вопросе, возможно, вы отредактировали ее в течение 5 минут после запроса, но на самом деле это микрооптимизация, и это обязательно не вызывать "снижение вдвое" в целом. Если вы не пишете их миллион раз в секунду (все же, почему вы хотите это сделать? Разве вы не злоупотребляете явлением "протоколированием"?).