Преобразование шестнадцатеричной строки в ByteBuffer с потоками Java 8 - PullRequest
0 голосов
/ 04 мая 2018

Я ищу способ читать шестнадцатеричные строки из файла строка за строкой и добавлять их как преобразованные байты в некоторый ByteBuffer.

ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

Files.lines(filePath).foreach( l -> 

        byteBuffer.put(
            // first of all strip newlines and normalize string
            l.replaceAll("/\n|\r/g", "").toUpperCase()

            // but what to do here?
            // is there something like
            //   take next 2 characters (-> Consumer)
            //   and replace them with the converted byte?
            //     E.g. "C8" -> 0xC8
            //   until the end of the string is reached
        )

);

На это ответили миллион раз. Но я задавался вопросом, есть ли решение, использующее потоки, подобные возвращаемым Files.lines().

Обычно мне нравится этот ответ. Кто-нибудь может мне помочь с переводом этого в потоковое решение java-8 или завершением моего примера сверху?

Спасибо!

Ответы [ 2 ]

0 голосов
/ 04 мая 2018

Это немного похоже на проблему xy , так как чтение файла « строка за строкой » уже является частью вашего попытки решения, в то время как фактическая задача не включает каких-либо требований к читать файл «построчно».

На самом деле вы хотите обработать все шестнадцатеричные числа источника, независимо от ограничителей строки, что является заданием для java.util.Scanner. Он также позволяет обрабатывать элементы с помощью Stream API, хотя эта конкретная задача не приносит от этого большой пользы по сравнению с циклом:

ByteBuffer bb = ByteBuffer.allocate(1024);
try(Scanner s = new Scanner(yourFile)) {
    s.findAll("[0-9A-Fa-f]{2}")
     .mapToInt(m -> Integer.parseInt(m.group(), 16))
     .forEachOrdered(i -> { if(bb.hasRemaining()) bb.put((byte)i); });
}
try(Scanner s = new Scanner(yourFile)) {
    Pattern p = Pattern.compile("[0-9A-Fa-f]{2}");
    for(;;) {
        String next = s.findWithinHorizon(p, 0);
        if(next == null) break;
        if(!bb.hasRemaining()) // the thing hard to do with Stream API
            bb = ByteBuffer.allocate(bb.capacity()*2).put(bb.flip());
        bb.put((byte)Integer.parseInt(next, 16));
    }
}

Обратите внимание, что в этих примерах используется Java 9. В Java 8 для Buffer, возвращаемого Buffer.flip(), требуется тип, приведенный к ByteBuffer, а Scanner.findAll недоступен, но должен быть заменен резервным портом. как в этот ответ .

0 голосов
/ 04 мая 2018

Вы можете использовать служебный метод для анализа строки как шестнадцатеричной строки в байтовом массиве:

public static byte[] hexStringToByteArray(String str) {
    if(str.startsWith("0x")) { // Get rid of potential prefix
        str = str.substring(2);
    }

    if(str.length() % 2 != 0) { // If string is not of even length
        str = '0' + str; // Assume leading zeroes were left out
    }

    byte[] result = new byte[str.length() / 2];
    for(int i = 0; i < str.length(); i += 2) {
        String nextByte = str.charAt(i) + "" + str.charAt(i + 1);
        // To avoid overflow, parse as int and truncate:
        result[i / 2] = (byte) Integer.parseInt(nextByte, 16);
    }
    return result;
}

ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

Files.lines(filePath).forEach( l -> 
    byteBuffer.put(
        hexStringToByteArray(l.replaceAll("/\n|\r/g", "").toUpperCase())
    )
);
...