使用Java 8流进行ByteBuffer转换的十六进制字符串

时间:2018-05-04 09:12:24

标签: java java-8 java-stream string-conversion

我正在寻找一种逐行读取文件中十六进制字符串的方法,并将它们作为转换后的字节附加到某些ByteBuffer。

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet"/>

<div class="ui-widget">
    <label for="tags">Tags:</label>
    <input id="tags" />
    <div id="tagsname"></div>
</div>

<button type="button" id="getValue">Get value</button>

已经回答了一百万次。但我想知道是否有使用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 ) ); 返回的流的解决方案。

一般来说,我喜欢this回答。任何人都可以帮我翻译成基于java-8流的解决方案或从上面完成我的例子吗?

谢谢!

2 个答案:

答案 0 :(得分:1)

您可以使用实用程序方法将行解析为字符串数组的十六进制字符串:

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())
    )
);

答案 1 :(得分:1)

这看起来有点像xy problem,因为读取文件“逐行”已经是您尝试的解决方案的一部分,而实际任务不包括任何阅读文件“逐行”。

实际上,您希望处理源的所有十六进制数,而不管行终结符,这是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不可用但是被this answer中的后端口替换。