[TUT] Creating a ByteString in Android

The protobuf library has a construct called ByteString. This is a immutable sequence of bytes, usually used to serialise a file or other piece of data. Recently when using the Google Cloud Speech to Text library I had to convert a local voice recording to this protobuf ByteString to be able to send it to the STT (Speech To Text) API. Let’s run through that together now.

Protobuf – ByteString

Immutable sequence of bytes. Substring is supported by sharing the reference to the immutable underlying bytes, as with String. Concatenation is likewise supported without copying (long strings) by building a tree of pieces in RopeByteString.Like String, the contents of a ByteString can never be observed to change, not even in the presence of a data race or incorrect API usage in the client code.

To start, we want to convert a file to a ByteString. Usually starting with the files location:

val location = "/sdcard/android/data/com.myapp/myfolder/voice.wav"
// this is actually getExternalFilesDir("myfolder")

To convert this to a ByteArray we first need to convert the File to a ByteString.

val byteArray = File(location).readBytes()

then use Protobufs inbuilt conversion methods to get the ByteString.

val byteString = ByteString.copyFrom(byteArray)

That’s it! You have created a ByteString from a File. Here is the code in full.

val location = "/sdcard/android/data/com.myapp/myfolder/voice.wav"
// this is actually getExternalFilesDir("myfolder")
val byteArray = File(location).readBytes()
val byteString = ByteString.copyFrom(byteArray)

You can also make use of Kotlins awesome extension functions to make this easier if you are doing it over and over.

Extension Function on File:

fun File.byteString(): ByteString = ByteString.copyFrom(this.readBytes())
// Now we can do:
val byteString = File(location).byteString()

Another extension function on File using String also:

fun String.byteString(): ByteString = File(this).byteString()
// Now we can do
val byteString = "/sdcard/android/data/com.myapp/myfolder/voice.wav".byteString()
// Be careful with this one, as its not too obvious that you want to get the byteString of the relative File and not the String itself 

Enjoy!