You Qi
You Qi

Reputation: 9211

Creating ByteArray in Kotlin

Is there a better/shorter way in creating byte array from constant hex than the version below?

byteArrayOf(0xA1.toByte(), 0x2E.toByte(), 0x38.toByte(), 0xD4.toByte(), 0x89.toByte(), 0xC3.toByte())

I tried to put 0xA1 without .toByte() but I receive syntax error complaint saying integer literal does not conform to the expected type Byte. Putting integer is fine but I prefer in hex form since my source is in hex string. Any hints would be greatly appreciated. Thanks!

Upvotes: 56

Views: 77559

Answers (5)

b0nyb0y
b0nyb0y

Reputation: 1446

Just to improve upon the accepted solution, I took an inspiration from here. Basically, since Kotlin declares its own Byte class, we can augment an operator onto its companion object, like so:

operator fun Byte.Companion.get(vararg ints: Int) = ByteArray(ints.size) { pos -> ints[pos].toByte() }

Then, you can declare a Byte array more "naturally":

val bytes = Byte[0xA1, 0x2E, 0x38, 0xD4, 0x89, 0xC3]

Upvotes: 4

user511824
user511824

Reputation: 326

I just do:

val bytes = listOf(0xa1, 0x2e, 0x38, 0xd4, 0x89, 0xc3)
    .map { it.toByte() }
    .toByteArray()

Upvotes: 7

Milack27
Milack27

Reputation: 1689

If all your bytes were less than or equal to 0x7F, you could put them directly:

byteArrayOf(0x2E, 0x38)

If you need to use bytes greater than 0x7F, you can use unsigned literals to make a UByteArray and then convert it back into a ByteArray:

ubyteArrayOf(0xA1U, 0x2EU, 0x38U, 0xD4U, 0x89U, 0xC3U).toByteArray()

I think it's a lot better than appending .toByte() at every element, and there's no need to define a custom function as well.

However, Kotlin's unsigned types are an experimental feature, so you may have some trouble with warnings.

Upvotes: 45

user10053723
user10053723

Reputation:

as an option you can create simple function

fun byteArrayOfInts(vararg ints: Int) = ByteArray(ints.size) { pos -> ints[pos].toByte() }

and use it

val arr = byteArrayOfInts(0xA1, 0x2E, 0x38, 0xD4, 0x89, 0xC3)

Upvotes: 54

zsmb13
zsmb13

Reputation: 89548

The issue is that bytes in Kotlin are signed, which means they can only represent values in the [-128, 127] range. You can test this by creating a ByteArray like this:

val limits = byteArrayOf(-0x81, -0x80, -0x79, 0x00, 0x79, 0x80)

Only the first and last values will produce an error, because they are out of the valid range by 1.

This is the same behaviour as in Java, and the solution will probably be to use a larger number type if your values don't fit in a Byte (or offset them by 128, etc).


Side note: if you print the contents of the array you've created with toInt calls, you'll see that your values larger than 127 have flipped over to negative numbers:

val bytes = byteArrayOf(0xA1.toByte(), 0x2E.toByte(), 0x38.toByte(), 0xD4.toByte(), 0x89.toByte(), 0xC3.toByte())
println(bytes.joinToString()) // -95, 46, 56, -44, -119, -61

Upvotes: 12

Related Questions