【问题标题】:turn my 32 character int into a 32 byte array as is in Java将我的 32 个字符 int 转换为 32 字节数组,就像在 Java 中一样
【发布时间】:2016-03-12 05:55:03
【问题描述】:

我想知道如何将我的 32 个字符 int 转换为一个 32 字节的数组。

例子:

我有这个整数:

int test = 123456789;

我想把它变成这样:

byte[] Write_Page_Four = new byte[] {  

                                (byte) 0x00, (byte) 0x00,
                                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
                                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
                                (byte) 0x00, (byte) 0x01, (byte) 0x23, (byte) 0x45,
                                (byte) 0x67, (byte) 0x89};

目前,我正在考虑将我的 int 拆分为 2,然后手动将它们分配给字节数组,但这样做时遇到了一些麻烦,我认为这不是解决我的问题的最佳做法。

这就是我的 ATM,它正在返回错误,但仍在进行中,我可以对此提出一些建议:

String test2 = "01";
String test1 = "0x"+test2; 
byte test =  Byte.valueOf(test1);
System.out.println("teeeeest-----"+test);

byte[] Write_Page_Four = new byte[] {(byte) test};

这个返回一个错误:

java.lang.NumberFormatException:对于输入字符串:“0x01”

【问题讨论】:

  • 这个数字太大了,无法用int(32 位)表示。除此之外,你想byte[] 代表文本,还是实际int 的字节?
  • @Paul 哎呀,你是对的,我应该明确指出,只有 9 位 int 会被使用,其余的前导数字都是 0。很抱歉。

标签: java arrays byte


【解决方案1】:

导致问题的原因

Byte.valueOf 不像 Java 编译器那样解析数据:它期望输入为十进制数。

但是,您可以使用带有任意基数的Byte.valueOf(String,int)。在这种情况下,您可以使用以下方法解决它:

byte test =  Byte.valueOf(test2,16); //using test2, not test1

注意不要在前面加上"0x"。然而,这是一种低效的方法。

整数是 32 位,而不是 32 字节

第二个问题是您声明可以将12345678901234567890123456789011 之类的数字存储到 int 中。你不能。 int 有 32 个。这意味着它的表示被限制在或多或少 2.1B。所以我认为你的意思是将12345678901234567890123456789011 存储在String 中?

数字系统

请注意,数字 12345678901234567890123456789011 在内部不表示为 (byte) 0x12, (byte) 0x34,...,除非您使用的是二进制编码的小数。这是因为计算机使用二进制数字系统(因此用十六进制表示对字节进行分组),而人类使用十进制表示。例如123456789 将表示为0x07,0x5B,0xCD 0x15

使用字节数组序列化 int(或其他数据结构)

您可以使用this codeint(和其他数据类型)转换为字节数组:

ByteBuffer b = ByteBuffer.allocate(4);
b.putInt(test);
byte[] result = b.array(); //result will be 4 bytes,
//since you can represent any int with four bytes.

或者,如果您想像这样表示int,您可以使用以下方法:

int t = test;
byte[] dat = new byte[5];//at most 5 bytes needed
for(int j = 4; test != 0; j--) {
    int rm = t%100;
    dat[j] = (byte) (rm%10+((rm/10)<<8));
    t /= 100;
}
//result is dat

【讨论】:

  • @makingitwork:仍然不完全清楚。请注意,一个字节代表0 和(包括)255 之间的数字。因此,您可以更有效地表示它(计算机会这样做,因为它也可以更有效地进行添加等)。例如,123456789 等同于 0x75bcd15
  • 对于此类问题,您建议的解决方案是什么?
  • 我的意思是对整个 int 值的混淆,我确实错过了:D,关于我的问题,我希望能够将我的 int 值按原样呈现为字节值,这就是为什么我尝试将 0x 附加到我的 int,我明白将字符串转换为字节会导致非常不同的结果,因为每个字符都有不同的字节表示。这就是为什么我希望我可以简单地将 0x 附加到我的数字并使它看起来像一个字节数据。
  • @makingitwork:很好的字符串操作往往效率很低。为了将int 序列化为byte[],我建议使用ByteBuffer 或Andreas 的解决方案(在语义上是等效的)。它将导致固定数量的位数和更少的位数。此外,它还可以防止人们重新发明轮子
  • 我的问题不是转换而是复制,我花了一段时间才意识到这一点。 :D 我找到了这个link 虽然我无法理解答案。
【解决方案2】:

我建议不要处理数字的文本表示,而是简单地计算单个数字:

每次取两位数:

int inp = 1234...;

for(int lowerBound = 1 ; lowerBound < Integer.MAX_VALUE ; lowerBound *= 100)
    //twoDigit contains two digits of the input-number
    int twoDigit = (inp /lowerBound) % 100;

将这两个数字转换为一个字节:

byte transform(int i){
    if(i == 0)
        return 0x00;

    int lsd = (i % 10); //least significant digit of the input (decimal)
    int msd = (i / 10); //most significant digit

    //merge lsd and msd into a single number, where the lower 4 bits are reserved for
    //lsd and the higher 4 bits for msd
    return lsd | (msd << 4);
}

完整的代码如下所示:

import java.util.Arrays;

public class test
{
    private static final int BYTES = 4;

    public static void main(String[] args){
        int v = 12345678;

        int at_arr = BYTES - 1;
        byte[] result = new byte[BYTES];//int is 32-bit/4 byte long

        for(int lowerBound = 1 ; lowerBound < Integer.MAX_VALUE && at_arr > -1; lowerBound *= 100, at_arr--)
            result[at_arr] = transformDigits((v / lowerBound) % 100);

        for(byte b : result)
            System.out.print(" 0x" + Integer.toString(b , 16) + ",");
        System.out.println();
    }

    static byte transformDigits(int i){
        if(i == 0)
            return 0x00;

        int lsd = (i % 10); //least significant digit of the input (decimal)
        int msd = (i / 10); //most significant digit

        //merge lsd and msd into a single number, where the lower 4 bits are reserved for
        //lsd and the higher 4 bits for msd
        return (byte) (lsd | (msd << 4));
    }
}

如果BYTES的类型和值得到适当更新,这段代码基本上可以用于任何整数类型。

【讨论】:

  • 请注意 OP 在数字系统之间存在问题。 1234... 不会生成 0x12,0x34,... 仅仅是因为它是十进制解释的,而 OP 想要十六进制解释它。不过 +1。
  • @CommuSoft OP 想要将 int 转换为代表它的原始字节。我只是提出了一种方式比转换为文本并解析回来更有效的方法。
  • 什么是非懒惰的方式?因为我计划实施一个令人满意的解决方案,而不是胶带解决方案。
  • @makingitwork 我想我现在明白了这个问题。我将编辑帖子,我的解决方案甚至无法满足您的需求。
  • @makingitwork 对错误感到抱歉,我已纠正了所有内容,最终版本具有正确的输出。除了输出看起来不太好,0x00 输出为0x0
【解决方案3】:

以下是将int 转换为byte[] 的方法:

int test = 123456789;

byte[] bytes = new byte[4];
bytes[0] = (byte)(test >> 24);
bytes[1] = (byte)(test >> 16);
bytes[2] = (byte)(test >> 8);
bytes[3] = (byte)test;

System.out.printf("%02x %02x %02x %02x%n", bytes[0], bytes[1], bytes[2], bytes[3]);

输出

07 5b cd 15

如果你愿意,你也可以内联它:

int test = 123456789;
byte[] bytes = new byte[] { (byte)(test >> 24),
                            (byte)(test >> 16),
                            (byte)(test >> 8),
                            (byte)test };
System.out.printf("%02x %02x %02x %02x%n", bytes[0], bytes[1], bytes[2], bytes[3]);

【讨论】:

  • 这确实是你应该序列化int的方式。问题是 OP 似乎考虑了不同的格式。无论如何 +1。
  • @CommuSoft 是的,这就是我展示结果的原因,因为它偏离了问题。你得到了我的 +1,因为它既提供了一个更简单的版本,又提供了一个更字面意义上的替代后续问题(尽管这对我来说意义不大)。
猜你喜欢
  • 2017-01-18
  • 2017-10-07
  • 2021-01-01
  • 1970-01-01
  • 2019-03-14
  • 1970-01-01
  • 1970-01-01
  • 2017-08-22
  • 2020-04-27
相关资源
最近更新 更多