How can I convert an Int to a ByteArray and then convert it back to an Int with Kotlin?
Asked Answered
L

6

11

Here is my code :

Int -> ByteArray

private fun write4BytesToBuffer(buffer: ByteArray, offset: Int, data: Int) {
    buffer[offset + 0] = (data shr 24).toByte()
    buffer[offset + 1] = (data shr 16).toByte()
    buffer[offset + 2] = (data shr 8).toByte()
    buffer[offset + 3] = (data shr 0).toByte()
}

ByteArray -> Int

private fun read4BytesFromBuffer(buffer: ByteArray, offset: Int): Int {
    return (buffer[offset + 0].toInt() shl 24) or
           (buffer[offset + 1].toInt() shl 16) or
           (buffer[offset + 2].toInt() shl 8) or
           (buffer[offset + 3].toInt() and 0xff)
}

It works without any problem for any value between -32,768 and 32,767. However, it doesn't work with larger values. For example :

val buffer = ByteArray(10)
write4BytesToBuffer(buffer, 0, 324)
read4BytesFromBuffer(buffer, 0) // It returns 324 ***OK***

val buffer = ByteArray(10)
write4BytesToBuffer(buffer, 0, 40171)
read4BytesFromBuffer(buffer, 0) // It returns -25365 ***ERROR***

Do you see where I went wrong?

Lully answered 20/4, 2021 at 12:47 Comment(1)
You can use Java's ByteBuffer as described here: #4485628Phago
L
15

Here is the solution.

Int -> ByteArray

private fun write4BytesToBuffer(buffer: ByteArray, offset: Int, data: Int) {
    buffer[offset + 0] = (data shr 0).toByte()
    buffer[offset + 1] = (data shr 8).toByte()
    buffer[offset + 2] = (data shr 16).toByte()
    buffer[offset + 3] = (data shr 24).toByte()
}

Or in a shorter way

for (i in 0..3) buffer[offset + i] = (data shr (i*8)).toByte()

ByteArray -> Int

private fun read4BytesFromBuffer(buffer: ByteArray, offset: Int): Int {
    return (buffer[offset + 3].toInt() shl 24) or
           (buffer[offset + 2].toInt() and 0xff shl 16) or
           (buffer[offset + 1].toInt() and 0xff shl 8) or
           (buffer[offset + 0].toInt() and 0xff)
}
Lully answered 23/4, 2021 at 12:27 Comment(3)
I am not sure it's correct, I have not tried it but I will thumbup before trying it because u r the first one to do this, I have been looking for an answer for a complete day :0Homeland
@MohammadElsayed It's correct. I tested it in every way. :) But if not, please let me know.Lully
I wrote for (i in 0..3) buffer[offset + i] = (data shr (i*8)).toByte()Mosier
S
15

I'd just use java.nio.ByteBuffer -

fun intToBytes(i: Int): ByteArray =
    ByteBuffer.allocate(Int.SIZE_BYTES).putInt(i).array()

fun bytesToInt(bytes: ByteArray): Int =
    ByteBuffer.wrap(bytes).int
Schuh answered 30/3, 2022 at 5:31 Comment(2)
This is nice, note that it defaults to ByteOrder.BIG_ENDIAN, otherwise use ByteBuffer.allocate(Int.SIZE_BYTES).putInt(i).order(ByteOrder.LITTLE_ENDIAN).array()Actinomorphic
@JohnCaron The call to .order() needs to be before .putInt() else it won't have an effectBaker
T
9

Here is an one liner that will give you a ByteArray:

fun numberToByteArray (data: Number, size: Int = 4) : ByteArray = 
    ByteArray (size) {i -> (data.toLong() shr (i*8)).toByte()}

Optionally setting the number of bytes (size), you can convert Shorts, Ints, Longs.

Just call it like this:

var yourByteArray = numberToByteArray (yourNumberHere)
Toile answered 9/11, 2021 at 0:45 Comment(2)
Should "item.toLong()" be "data.toLong()"?Precipitancy
Damn, Kotlin has no in-built class for converting types to bytes like C#'s BitConverter which existed for like 2 decades, and I have to create these methods for each type? This is unexpected... I thought this is a very basic need.Ronn
S
0

you can write an extension function for that:

fun ByteArray.getIntAt(i: Int): Int {
    return (this[i].toInt() and 0xFF) or
            ((this[i + 1].toInt() and 0xFF) shl 8) or
            ((this[i + 2].toInt() and 0xFF) shl 16) or
            ((this[i + 3].toInt() and 0xFF) shl 24)
}

now you can use it:

val myInt = myByteArr.getIntAt(myIndex)

and vice versa:

private fun Int.toByteArray(): ByteArray {
    return byteArrayOf(
        (this and 0xFF).toByte(),
        ((this shr 8) and 0xFF).toByte(),
        ((this shr 16) and 0xFF).toByte(),
        ((this shr 24) and 0xFF).toByte()
    )
}

and use it:

val myByteArray = myInt.toByteArray()
Sunn answered 31/7, 2023 at 12:2 Comment(0)
C
0

In case you need control of the allocated bytes size it is possible to optimize array size by analyzing value range:

fun Int.toBytes(size: Int = Int.SIZE_BYTES): ByteArray = when {
    size == Byte.SIZE_BYTES -> byteArrayOf(this.toByte())
    size in Short.SIZE_BYTES until Int.SIZE_BYTES -> ByteBuffer.allocate(size).order(ByteOrder.BIG_ENDIAN).putShort(this.toShort()).array()
    size >= Int.SIZE_BYTES -> ByteBuffer.allocate(size).order(ByteOrder.BIG_ENDIAN).putInt(this).array()
    else -> throw IllegalArgumentException("Bytes size $size can not be empty or negative")
}

fun ByteArray.toInt(): Int = when {
    size == Byte.SIZE_BYTES -> first().toInt()
    size in Short.SIZE_BYTES until Int.SIZE_BYTES -> ByteBuffer.wrap(this).getShort().toInt()
    size >= Int.SIZE_BYTES -> ByteBuffer.wrap(this).getInt()
    else -> throw IllegalArgumentException("ByteArray is empty")
}

For me it was helpful while writing/reading arrays into a file with leading information with size.

My tests:

    @Test
    fun `int is converted to byte array and back`() {
        assertEquals(-127, -127.toBytes(1).toInt())
        assertEquals(0, 0.toBytes(1).toInt())
        assertEquals(1, 1.toBytes(1).toInt())
        assertEquals(2, 2.toBytes(1).toInt())
        assertEquals(3, 3.toBytes(1).toInt())
        assertEquals(4, 4.toBytes(1).toInt())
        assertEquals(5, 5.toBytes(1).toInt())
        assertEquals(127, 127.toBytes(1).toInt())
        assertEquals(128, 128.toBytes(2).toInt())
        assertEquals(1114, 1114.toBytes(3).toInt())
        assertEquals(98754332, 98754332.toBytes(4).toInt())
    }

Btw, it is recommended to use bit-shifting operations in that case only for educational purposes. So utilizing ByteBuffer offers better performance for larger conversions.

If performance is critical, consider exploring native libraries.

Creighton answered 26/2, 2024 at 14:14 Comment(0)
B
0

I've created 2 extension functions, based on this answer https://mcmap.net/q/957328/-how-can-i-convert-an-int-to-a-bytearray-and-then-convert-it-back-to-an-int-with-kotlin

private fun Int.toByteArray(): ByteArray =
    ByteBuffer.allocate(Int.SIZE_BYTES).putInt(this).array()

private fun ByteArray.toInt(): Int =
    ByteBuffer.wrap(this).int
Boldface answered 2/4, 2024 at 12:21 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.