Как преобразовать массив байтов в читаемый человеком формат?

Я использую алгоритм "Blowfish" для шифрования и расшифровки содержимого текста. Я вставляю зашифрованное содержимое в изображение, но при извлечении я получаю массив байтов, который передаю его методу update класса Шифр ​​.

Но метод возвращает массив байтов, который я хочу преобразовать обратно в понятную для человека форму.
Когда я использую метод write FileOutputStream, он работает нормально, когда предоставляется имя файла.
Но теперь я хочу распечатать его на консоли в удобном для чтения формате. Как пройти через это? Я тоже пытался использовать ByteArrayOutputStream. Но не получилось.

Спасибо.

Ответ 1

byte[] byteArray = new byte[] {87, 79, 87, 46, 46, 46};

String value = new String(byteArray);

Ответ 2

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

for(byte foo : arr){
    System.out.print(foo + " ");
}

Или, если вы хотите увидеть шестнадцатеричные значения, вы можете использовать printf:

System.out.printf("%02x ", foo);

Если вы хотите увидеть строку, которую представляет массив байтов, вы можете просто сделать

System.out.print(new String(arr));

Ответ 3

Вы можете преобразовать bytearray в строку, содержащую шестнадцатеричные значения байтов используя этот метод. Это даже работает на java < 6

public class DumpUtil {

     private static final String HEX_DIGITS = "0123456789abcdef";

     public static String toHex(byte[] data) {
        StringBuffer buf = new StringBuffer();

        for (int i = 0; i != data.length; i++) {
            int v = data[i] & 0xff;

            buf.append(HEX_DIGITS.charAt(v >> 4));
            buf.append(HEX_DIGITS.charAt(v & 0xf));

            buf.append(" ");
        }

        return buf.toString();
    }   
}

Ответ 4

byte[] data = new byte[] {1, 2, 3, 4};
System.out.printf( Arrays.toString( data ) );

[1, 2, 3, 4]

Ответ 5

Лучше сделать hexDump, чтобы массив байтов

private static final byte[] HEX_CHAR = new byte[] { '0', '1', '2', '3',
            '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
public static final String dumpBytes(byte[] buffer) {
        if (buffer == null) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        sb.setLength(0);
        for (int i = 0; i < buffer.length; i++) {
            sb.append((char) (HEX_CHAR[(buffer[i] & 0x00F0) >> 4]))
                    .append((char) (HEX_CHAR[buffer[i] & 0x000F])).append(' ');
        }
        return sb.toString();
    }

Ответ 6

Это не тривиальная задача, как полагают многие. Каждый байт имеет значения в диапазоне от -128 до 127. Большинство из них являются непечатаемыми символами.

Чтобы кодировать байты в удобочитаемом формате, вы должны понимать, что в нем всего 62 буквенно-цифровых символа. Невозможно, чтобы ОДИН БАЙТ отображался на ОДИН символ, читаемый человеком, поскольку существует больше возможных байтов, чем 62 символа, которые человек может легко прочитать.

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

Это делает преобразование кусками от 1 до 7 входных байтов. Не может использовать более 7 байтов, это максимум для наибольшего значения Java. И я использую длинные значения, когда делаю преобразование.

Если фрагмент, например, имеет размер 5, то для кодирования фрагмента из 5 байтов требуется 7 буквенно-цифровых символов. Таким образом, размер вывода будет больше, чем размер ввода.

import org.slf4j.Logger;

/**************************************************************************************************************
 * Convert bytes into human readable string using provided alphabet.
 * If alphabet size 62 chars and byte chunk is 5 bytes then we need 7 symbols to encode it.
 * So input size will be increased by 40% plus 7 symbols to encode length of input
 *
 * Basically we do conversion from base255 (byte can has 255 different symbols) to base of a a size of the
 * given alphabet
 *
 * @author Stan Sokolov
 * 10/9/19
 **************************************************************************************************************/
public class HumanByte {
final static private Logger logger = org.slf4j.LoggerFactory.getLogger(OsmRouting.class);

// those are chars we use for encoding
private final static String DEFAULT_ALPHABET = "0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";

private char[] ALPHABET;
private int BASE;
private int[] POSITIONS;
private int CHUNK;
private int PW;
private long[] POWERS; // {916132832, 14776336, 238328, 3844, 62, 1};
private long[] MASKS; //(0xFF000000L & (input[0] << 24)) | (0xFF0000L & input[1] << 16) | (0xFF00L & input[2] << 8) | (0xFFL & input[3]);


/**************************************************************************************************************
 * Default constructor, with default alphabet and default chunk
 **************************************************************************************************************/
public HumanByte() {
    this(DEFAULT_ALPHABET, 5);
}

/**************************************************************************************************************
 *   Setup encoding using provided alphabet and chunk size
 **************************************************************************************************************/
public HumanByte(final String alphabet, int chunk) {
    if (chunk>7){
        chunk=7;
    }
    if (chunk<1){
        chunk=1;
    }
    this.ALPHABET = alphabet.toCharArray();
    BASE = alphabet.length();

    CHUNK = chunk;
    long MX = (long) Math.pow(255, CHUNK);
    PW = logBase(MX);
    int max=0;
    for (int i = 0; i < ALPHABET.length; i++) {
        if (max<ALPHABET[i]) max=ALPHABET[i];
    }
    POSITIONS = new int[max+1];
    logger.debug("BASE={}, MX={}, PW={}", BASE, MX, PW);
    for (int i = 0; i < ALPHABET.length; i++) {
        POSITIONS[ALPHABET[i]] = i;
    }
    POWERS = new long[PW]; //these are the powers of base to split input number into digits of its base
    for (int i = 0; i < PW; i++) {
        POWERS[i] = (long) Math.pow(BASE, PW - i - 1);
    }
    MASKS = new long[CHUNK];
    for (int i = 0; i < CHUNK; i++) { //this is how we are going to extract individual bytes from chunk
        MASKS[i] = (0xFFL << ((CHUNK - i - 1) * 8));
    }
}


/**************************************************************************************************************
 *  take bytes, split them in group by CHUNK, encode each group in PW number of alphabet symbols.
 **************************************************************************************************************/
public String encode(final byte[] input) {
    final StringBuilder output = new StringBuilder(); //will save output string here
    output.append(word(input.length)); // first write length of input into output to know exact size

    byte[] byte_word;
    for (int i = 0; i < input.length; ) {
        byte_word = new byte[CHUNK];
        for (int j = 0; j < CHUNK; j++) {
            if (i < input.length) {
                byte_word[j] = input[i++]; //remove negatives
            }
        }
        final long n = bytes2long(byte_word); //1099659687880

        final char[] w = word(n);
        output.append(w);

    }
    return output.toString();
}

/**************************************************************************************************************
 *   decode input
 **************************************************************************************************************/
public byte[] decode(final String in) {
    final int size = (int) number(in.substring(0, PW).toCharArray());
    final byte[] output = new byte[size];

    int j = 0, k = in.length();
    for (int i = PW; i < k; i += PW) {
        final String w = in.substring(i, i + PW);
        final long n = number(w.toCharArray());
        for (byte b : long2bytes(n)) {
            if (j < size) {
                output[j++] = b;
            }
        }
    }
    return output;
}

/**************************************************************************************************************
 * @return take 4 numbers from 0 to 255 and convert them in long
 **************************************************************************************************************/
private long bytes2long(byte[] input) {
    long v = 0;
    for (int i = 0; i < CHUNK; i++) {
        v |= ((long) (input[i]+ 128) << (8 * (CHUNK - i - 1)) & MASKS[i]); //+128 to remove negatives
    }
    return v;
}

/**************************************************************************************************************
 * @return take 4 numbers from 0 to 255 and convert them in long
 **************************************************************************************************************/
private byte[] long2bytes(long input) {
    final byte[] bytes = new byte[CHUNK];
    for (int i = 0; i < CHUNK; i++) {
        long x = MASKS[i] & input;
        long y = 8 * (CHUNK - i - 1);
        long z = (x >> y) - 128;
        bytes[i] = (byte) z;
    }
    return bytes;
}


/**************************************************************************************************************
 *  create word using given alphabet to represent given number built out of CHUNK bytes
 **************************************************************************************************************/
private char[] word(final long n) {
    final char[] output = new char[PW];
    long v=n;
    for (int i = 0; i < PW; i++) {
        final long pn = v / POWERS[i];
        output[i] = ALPHABET[(int) pn];
        long x = pn * POWERS[i];//900798402816 196327857024 2368963584 16134768 267696 1716 52
        v -= x;
    }
    return output;
}

/**************************************************************************************************************
 *   take string that contain number encoded in alphabet and return
 **************************************************************************************************************/
private long number(final char[] s) {
    long number = 0;
    for (int i = 0; i < PW; i++) {
        long x =  (long) POSITIONS[s[i]];
        long y = POWERS[i];
        long z = x*y;
        number +=  z;
    }
    return number;
}

private int logBase(long num) {
    return (int) Math.ceil(Math.log(num) / Math.log(BASE));
}
}