将十六进制字节转换为实际字节[重复]

Posted

技术标签:

【中文标题】将十六进制字节转换为实际字节[重复]【英文标题】:Convert byte in hex to actual byte [duplicate] 【发布时间】:2015-07-03 09:41:38 【问题描述】:

我有一个像这样用字节写的文件

\r\x00\x00\x00\xd0"a": "test"

有以下字节

[13, 0, 0, 0, -48, 123, 34, 97, 34, 58, 32, 34, 116, 101, 115, 116, 34, 125]

当这个文件被读入 Java 时,我得到了所有的转义

\\r\\x00\\x00\\x00\\xd0"a": "test"

当我在这个字符串上执行.getBytes() 时,我得到了

[92, 114, 92, 120, 48, 48, 92, 120, 48, 48, 92, 120, 48, 48, 92, 120, 100, 48, 123, 34, 97, 34, 58, 32, 34, 116, 101, 115, 116, 34, 125]

我必须将字符串转换为有效字节,不幸的是我无法更改文件的读取方式。我知道在 Python 中,你用'rb' 模式打开一个文件,你就可以开始了。如果java有这个能力,我就用不上。

简而言之,如何将 Java 读取的字符串转换为写入文件的原始字节数组?

对不起,如果这个问题很简单,但我对 Java 很陌生。

编辑:所以我相信我的问题与建议的“重复问题”链接不同。它不会获取 java 字符串中的每个文字值并将其转换回一个字节。 java中的字符串已被读者转义。 \x00 现在是 \\x00,这不是同一个字节值。所以我想我需要一些方法来取消转义字符串?

在十六进制编辑器中查看的文件

0000000: 5c72 5c78 3030 5c78 3030 5c78 3030 5c78  \r\x00\x00\x00\x
0000010: 6430 7b22 6122 3a20 2274 6573 7422 7d0a  d0"a": "test".

在十六进制编辑器中查看 java 的字符串

0000000: 5c5c 725c 5c78 3030 5c5c 7830 305c 5c78  \\r\\x00\\x00\\x
0000010: 3030 5c5c 7864 307b 2261 223a 2022 7465  00\\xd0"a": "te
0000020: 7374 227d 0a                             st".

【问题讨论】:

经过充分解释和格式化的问题绝不是愚蠢的,至少对我来说是这样。 你读的怎么样? 您从 getBytes() 获得的结果是您所期望的吗? @Shar1er80 第一个数组是我所期待的。 来吧,这个问题每天都会被问到,请 VTC-duplicate 【参考方案1】:

在 Java 中,您将不得不解释输入字符串以获得所需的字节值。

我编写了一个解释输入字符串的 Java 应用程序。

这是输入字符串:

\r\x00\x00\x00\xd0"a": "test"

结果如下:

[13, 0, 0, 0, -48, 34, 97, 34, 58, 32, 34, 116, 101, 115, 116, 34, 125]

这是代码。您可能需要稍微修改代码以处理您没有提出问题的情况。

package com.ggl.testing;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ConvertBytes implements Runnable 

    private String fileName;

    public static void main(String[] args) 
        new ConvertBytes("bytes.txt").run();
    

    public ConvertBytes(String fileName) 
        this.fileName = fileName;
    

    @Override
    public void run() 
        BufferedReader br = null;

        try 
            br = new BufferedReader(new InputStreamReader(getClass()
                    .getResourceAsStream(fileName)));
            String line = "";
            while ((line = br.readLine()) != null) 
                processLine(line);
            
         catch (FileNotFoundException e) 
            e.printStackTrace();
         catch (IOException e) 
            e.printStackTrace();
         finally 
            try 
                if (br != null) 
                    br.close();
                
             catch (IOException e) 
                e.printStackTrace();
            
        
    

    private void processLine(String line) 
        String[] parts = line.split("(?=\\\\)");
        List<Byte> byteList = new ArrayList<Byte>();

        for (int i = 0; i < parts.length; i++) 
            if (parts[i].equals("")) 
                continue;
             else 
                byteList.addAll(getValue(parts[i]));
            
        

        Byte[] bytes = byteList.toArray(new Byte[byteList.size()]);
        System.out.println(Arrays.toString(bytes));
    

    private List<Byte> getValue(String s) 
        List<Byte> byteList = new ArrayList<Byte>();

        if (s.startsWith("\\x")) 
            int value = Integer.valueOf(s.substring(2, 4), 16);
            if (value > 127) 
                value = value - 256;
            
            byteList.add(Byte.valueOf((byte) value));
            if (s.length() > 4) 
                byteList.addAll(getAsciiValue(s.substring(4)));
            
         else if (s.equals("\\r")) 
            byteList.add(Byte.valueOf((byte) 13));
         else if (s.equals("\\t")) 
            byteList.add(Byte.valueOf((byte) 9));
         else 
            byteList.addAll(getAsciiValue(s));
        

        return byteList;
    

    private List<Byte> getAsciiValue(String s) 
        List<Byte> byteList = new ArrayList<Byte>();

        for (int i = 0; i < s.length(); i++) 
            int value = (int) s.charAt(i);
            byteList.add(Byte.valueOf((byte) value));
        

        return byteList;
    


bytes.txt 文件必须与 Java 应用程序位于同一目录中。

【讨论】:

【参考方案2】:

看来您必须自己解析“字符串”行。

我会有一个转义字符映射('\r'、'\n'、'\b' 等...)

private static Map<String, Byte> escapedCharacters; 
static 
    escapedCharacters = new HashMap<>();
    escapedCharacters.put("\\b", (byte)'\b');
    escapedCharacters.put("\\f", (byte)'\f');
    escapedCharacters.put("\\n", (byte)'\n');
    escapedCharacters.put("\\r", (byte)'\r');
    escapedCharacters.put("\\t", (byte)'\t');
    // Add more if needed
;

然后如下处理你的文件:

public static void main(String[] args) throws Exception 
    String myFile = "PathToYourFile";

    // Read your file in
    List<String> myFileLines = Files.readAllLines(Paths.get(myFile));

    // List to hold all the lines as translated bytes
    List<byte[]> myFileLinesAsBytes = new ArrayList<>();
    for (String line : myFileLines) 
        myFileLinesAsBytes.add(translateEscapedBytes(line));
    

    // Displays all translated lines
    for (byte[] byteLine : myFileLinesAsBytes) 
        System.out.println(Arrays.toString(byteLine));
    
    System.out.println();


private static byte[] translateEscapedBytes(String line) throws UnsupportedEncodingException 
    List<Byte> translatedBytes = new ArrayList<>();
    for (int i = 0; i < line.length();) 
        if (line.charAt(i) == '\\')  // Escaped byte
            String escapedByte = line.substring(i, i + 2);
            if (escapedByte.endsWith("x"))  // Hexidecimal number
                escapedByte = line.substring(i + 2, i + 4); // + 4 to get the two numbers after \x
                translatedBytes.add(hexStringToByte(escapedByte));
                i += 4;
             else  // Escaped character
                translatedBytes.add(escapedCharacters.get(escapedByte));
                i += 2;
            
         else  // Non Escapted Character
            translatedBytes.add((byte)(line.charAt(i)));
            i++;
        
    

    // Copy List to actual byte[] to return
    byte[] result = new byte[translatedBytes.size()];
    for (int i = 0; i < translatedBytes.size(); i++) 
        result[i] = translatedBytes.get(i);
    
    return result;


private static byte hexStringToByte(String s) 
    return (byte) ((Character.digit(s.charAt(0), 16) << 4) + Character.digit(s.charAt(1), 16));

translatedEscapedBytes() 在字符串中查找“\”字符并识别与下一个字符组合的字符,您将得到一个转义字符。如果转义字符是 \x,那么您知道接下来的两个数字是需要转换为字节 (hexStringToByte(String s)) 的十六进制数,否则使用转义字符映射将转义字符转换为字节。所有其他字符都被视为非转义字符,只是被转换为它们的字节值。

结果(使用您提供的数据):

【讨论】:

【参考方案3】:

在 Java 中读取文件时,您不会得到“所有内容都已转义”。为什么你这么想?转换为字节表明String 包含的正是十六进制编辑器在文件中显示的内容。换句话说,

92、114、92、120、48、48、92、120、48、48、92、120、48、48、92、120(十进制)

一样

5c72 5c78 3030 5c78 3030 5c78 3030 5c78(十六进制)

如果您想解码文件中的转义序列,您需要编写一些代码来处理它们;这不是字符编码问题。

【讨论】:

以上是关于将十六进制字节转换为实际字节[重复]的主要内容,如果未能解决你的问题,请参考以下文章

将字符串转换为十六进制字节数组[重复]

在android中将字节[]转换为十六进制字符串[重复]

我正在使用二进制阅读器将字符串转换为字节,如何将字节反转回相同的字符串 [重复]

字节数组到十六进制字符数组的转换[重复]

如何将字符串转换为十六进制字节数组? [复制]

在Java中从整数转换为二进制时保留整个字节[重复]