Преобразование необработанных байтов в строку

у меня есть эта проблема в моем Java-коде, и я как бы застрял в своем решении, поэтому я хочу преобразовать необработанные байты, которые я захватил из инструмента сетевого анализатора (wireshark), в строковое реальное значение байтов

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

String array= "6549534f3030363030303036303038303038323230303030303030303030303030303430303030303030303030303030303034313830373432313730303030303130303103";
        char[] ch=array.toCharArray();
        String charTemp = "";
        byte[] byteArray= {};

        for (int i = 0; i < ch.length; i++) {
            if (i%2==0) {
                System.out.println(charTemp);
                System.out.println(byteArray.length);
                byteArray[byteArray.length]=(int) charTemp;
                charTemp = "";
            }
            charTemp+=ch[i];
            System.out.print(ch[i] + " ");
        }

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

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
91
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Здесь есть как минимум 4 проблемы, и, кроме того, это не особенно эффективный алгоритм (не то чтобы это имело значение).

объединение значения ASCII с цифрой

Символ 6 на самом деле имеет значение 54. Нет, правда:

char c = '6';
int v = (int) c;
System.out.println(v); // this would print 54.

В конце концов, персонаж может быть на «А». Каким «числом» это должно стать? В компьютерных системах любой символ ищется в гигантской таблице, которая соответствует символу (например, а, или 5, или пробелу, или вводу, или ç, или é, или ☃, или даже 😀) числу.

И СИМВОЛ (или символ, если вы предпочитаете эту терминологию) «6» в этой таблице связан с кодом 54.

Пытаюсь преобразовать строку в int

charTemp - это строка, которая в конечном итоге будет содержать, например. "4f". Это 2 числа. Java правильно определяет, что попытка привести это к типу int не имеет смысла. (даже если строка содержит только 1 символ, java делает это - компилятор знает, что вы не можете преобразовать строки в int путем приведения, он не удосуживается проверить, может ли в этом случае это иметь какое-то подобие смысла. Это МОЖЕТ не имеет смысла, поэтому вы не можете этого сделать).

Что вы хотите, так это преобразовать строку «4f» в ее значение. «4f» — это просто число в строковой форме, как и «100». За исключением того, что это число по основанию 16, а не по основанию 10. Тем не менее, это число.

Итак, как нам превратить числа в строках в их значения? С Integer.parseInt, конечно. У которого есть вариант, где вы указываете базу. Так:

int v = Integer.parseInt("9", 16); // 16 = the base
System.out.println(v); // prints 9
v = Integer.parseInt("f", 16);
System.out.println(v); // prints 15. That's nice.
v = Integer.parseInt("4f", 16);
System.out.println(v); // Prints out 79. Which is what you wanted, I guess.

байты и целые

Вы не можете присвоить значение int в массиве байтов — вы выполняете приведение к int. Как только вы исправите все вышеперечисленное, вам все равно придется заменить это на (byte).

Вы ошибочно думаете, что массивы могут расти в java

Ваш массив байтов пуст. Массивы в java имеют фиксированный размер, поэтому, когда вы их создаете, они пусты и не могут быть увеличены, поэтому они застряли там. x[x.length] ВСЕГДА будет вызывать ArrayIndexOutOfBoundsException (поскольку длина массива — это первый индекс, который НЕ работает). В конце концов, массив, скажем, длины 3 имеет 3 индекса: 0, 1 и 2. Сам по себе 3 недействителен. Таким образом, byteArray[0] = ... потерпит крах.

Одним из решений является надлежащее предварительное определение размера массива байтов: byte[] byteArray = new byte[array.length() / 2];

И вам придется использовать byteArray[i / 2] = Integer.parseInt(charTemp, 16);

Весь этот код, вероятно, не нужен

Существуют инструменты и библиотеки, которые считывают массивы байтов, отформатированные как шестнадцатеричные строки (также известные как строки с перерезанными строками), вам не нужно писать этот код. См. этот ответ SO для получения дополнительной информации, потому что это то, что вы пытаетесь (предположительно) сделать здесь.

Объяснение шестнадцатеричного счета

Начинайте считать, как будто мы играем в прятки. 1, 2, 3, 4,...

Что будет после 8? Мы добираемся до 9. Достаточно легко.

Почему мы идем к "10" - 2 отдельных символа, когда нам нужно считать больше 9?

Кто знает - предположительно, потому что у нас, людей, 10 пальцев. Собственно, во времена Римской империи, но за ее пределами, число 12 было гораздо более распространенным. Выньте большой палец и начните считать сегменты пальцев. У вас по 3 на каждом из 4 оставшихся пальцев — это простой способ следить за счетом до 12.

У этих северных народов были символы для 12 цифр (от 0 до 11). Так же, как вы привыкли иметь 10 цифр (0, до 9). Когда у вас «кончаются цифры», вы просто добавляете «место» — мы начинаем считать, сколько раз мы использовали все цифры. «24» просто означает, что у нас закончились цифры дважды (то есть 10, каждый раз, то есть 20), а затем еще 4.

Компьютеры любят считать в двоичном формате. 0, 1... и у нас закончились цифры. Итак, компьютеры идут 0, 1, 10, 11, 100, 101 и так далее. Но это очень быстро становится громоздким, и его трудно «отследить» человеку.

Итак, мы идем на компромисс и используем вместо этого шестнадцатеричный формат. Это считается, как если бы у вас было 16 пальцев. Вы идете 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f. А потом у нас кончились цифры, поэтому число после этого (итак, 16, в десятичном виде!) — пишется как «10». Точно так же, как когда эти старые викинги писали «1» и «0», когда они начинали считать 12-е число, с помощью шестнадцатеричного числа вы получаете «1» и «0», когда доходите до 16-го числа.

И это то, что вы пытаетесь проанализировать здесь. Обратите внимание, например, что ваш ввод содержит «4f». Это "ф" не буква. Это «9» (последняя цифра) шестнадцатеричной системы счисления.

Привет, спасибо за ваше подробное объяснение моего кода, не могли бы вы объяснить мне эту часть except, it's in base 16, instead of base 10, потому что я не знаком с байтами, хотя хе-хе

mc ser 20.04.2023 13:45

Спасибо @rzwitserloot за объяснение, как будто мне 5 лет, есть ли какое-нибудь объяснение, как работает байт?

mc ser 27.04.2023 15:59

Эти разговоры о 10 пальцах и о том, как компьютеры считают, что у них 16 пальцев, объясняют разницу между основанием 16 и основанием 10. Байт состоит всего из 8 бит (или 2 шестнадцатеричных цифр). Точно так же, как если я попрошу вас записать число, используя не более 2 цифр, вы ограничены 0-99, с шестнадцатеричным числом вы ограничены 0-ff. ff равно 15*16 + 15 = 255 (поскольку 99 равно 9*10 + 9 = 99, принцип тот же).

rzwitserloot 27.04.2023 16:39

4 бита - это одна шестнадцатеричная цифра, потому что 4 цифры по основанию 2 (основание 2 = 0 или 1, это все цифры, которые у вас есть, нет 2, мы идем 0, 1, 10, 11, 100, 101 и т. д. ) составляет 2^4 = 16 различных вариантов (запишите их все; учитывая 4 цифры 0/1, сколько комбинаций вы можете составить? 16. Точно так же, как при наличии 2 цифр 0-9, вы можете составить 100 комбинаций: 0-99). 16 вариантов? Эй, вот сколько цифр в шестнадцатеричном формате - так что 8 бит становятся 2 шестнадцатеричными цифрами. Поскольку 10 не является коэффициентом 2, десятичные цифры здесь «не работают», поэтому информатика любит шестнадцатеричные цифры.

rzwitserloot 27.04.2023 16:41

На самом деле, что меня смущает, так это эта строка кода byteArray[i / 2] = (byte) ((Character.digit(ch[i], 16) << 4) + Character.digit(ch[i + 1], 16));, почему мне нужно сдвинуть ее, вместо того, чтобы просто соединить оба шестнадцатеричных кода, как byteArray[i / 2] = (byte) (Character.digit(ch[i], 16) + Character.digit(ch[i + 1], 16)); какая причина для этого?

mc ser 27.04.2023 19:02

Если я дам вам цифру «5» и цифру «2» и попрошу вас сложить их вместе, вы получите 52. Вы предлагаете сделать «5 + 2», что даст 7. Вам нужно умножить это «5» на 10, потому что он находится на месте «10». Эта первая цифра находится в разряде «10», но в шестнадцатеричном формате, поэтому * 16 вместо * 10. <<4 — это то же самое, что и *16.

rzwitserloot 27.04.2023 19:22

Хорошо, теперь я могу понять, спасибо

mc ser 30.04.2023 15:49

Как вы упомянули, существует проблема приведения типов, поскольку вы не можете преобразовать charTemp, который является String, в int. Помимо этого есть некоторые проблемы, которые я вижу.

  1. Длина byteArray всегда равна 0. Следовательно, byteArray[byteArray.length] не имеет никакого смысла.
  2. Поскольку ваши входные байты (array) находятся в шестнадцатеричном формате, вам нужен способ правильной обработки шестнадцатеричных значений.

Я бы предложил такой подход,

String array = "6549534f3030363030303036303038303038323230303030303030303030303030303430303030303030303030303030303034313830373432313730303030303130303103";
char[] ch = array.toCharArray();
System.out.println(Arrays.toString(ch));

int length = ch.length;
byte[] byteArray = new byte[length / 2];

for (int i = 0; i < ch.length; i += 2) {
    byteArray[i / 2] = (byte) ((Character.digit(ch[i], 16) << 4)
            + Character.digit(ch[i + 1], 16));
}
String string = new String(byteArray);
System.out.println(string);

Изменения, которые я сделал,

  • Удалено charTemp так как оно не понадобится.
  • Инициализирован byteArray до половины длины ch.
  • Изменен цикл for, чтобы перебирать все остальные элементы вместо проверки i%2 в теле цикла for.
  • Используется метод Character.digit() для обработки шестнадцатеричных значений.
  • Создал строку string со сгенерированным byteArray, чтобы ее можно было использовать в качестве вывода.

Это должно работать нормально.

Привет, chameerar, я понял большую часть вашего решения, но у меня есть кое-что, чего я не понимаю в этой части (Character.digit(ch[i], 16) << 4 можете ли вы объяснить, что вы пытаетесь сделать, особенно с << я не знаком с этим оператором, спасибо

mc ser 20.04.2023 16:01

@mcser Часть Character.digit(ch[i], 16) выводит значение ch[i] (это первая цифра HEX-числа в вашем array) в системе счисления 16. << — это побитовый оператор сдвига влево. Это добавляет четыре конечных нуля к значению. Это дает место для добавления второй цифры HEX-числа (то есть ch[i+1]), чтобы она формировала желаемое значение байта.

chameerar 21.04.2023 19:41

Привет, извините за длинный ответ, я до сих пор не понимаю побитового оператора сдвига влево, но когда я отлаживаю его с помощью этого кода System.out.println((Character.digit(ch[i],16) << 3) + " " +(Character.digit(ch[i],16) << 4)+ " " + ch[i]); , результат странный, есть ли какое-нибудь руководство, которое поможет мне понять этот побитовый оператор, чтобы я мог понять?

mc ser 27.04.2023 15:56

Конечно. Это будет полезно. geeksforgeeks.org/shift-operator-in-java/amp/?ref=gcse

chameerar 27.04.2023 23:02

Другие вопросы по теме