You can use the writeBytes function:
fun File.writeBytes(array: ByteArray)
Answer from André Jesus on Stack OverflowAbout write a UByteArray to the file - Libraries - Kotlin Discussions
android - Converting a byte array to a pdf file then saving it - Stack Overflow
android - kotlin reading from file into byte array - Stack Overflow
android - Create file from Byte Array sent inside JSON Object kotlin - Stack Overflow
This will get the Android download directory and write the byte array as a PDF file (assuming the byte array contains a PDF). Change File.createTempFile to any file you like (you don't need to create a temporary file):
fun writeBytesAsPdf(bytes : ByteArray) {
val path = requireContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
var file = File.createTempFile("my_file",".pdf", path)
var os = FileOutputStream(file);
os.write(bytes);
os.close();
}
You will also have to add android.permission.WRITE_EXTERNAL_STORAGE to your manifest.
Looking at How to download PDF file with Retrofit and Kotlin coroutines?, you can use:
private const val BUFFER_SIZE = 4 * 1024
private fun copyStreamToFile(inputStream: InputStream, outputFile: File) {
inputStream.use { input ->
val outputStream = FileOutputStream(outputFile)
outputStream.use { output ->
val buffer = ByteArray(BUFFER_SIZE)
while (true) {
val byteCount = input.read(buffer)
if (byteCount < 0) break
output.write(buffer, 0, byteCount)
}
output.flush()
}
}
}
or
private fun InputStream.saveToFile(file: String) = use { input ->
File(file).outputStream().use { output ->
input.copyTo(output)
}
}
Also you should create the file.
private fun createFile(context: Context, name: String): File? {
val storageDir = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.path
var file = File("$storageDir/$name.pdf")
return storageDir?.let { file }
}
The easiest way is to use
File("aaa").readBytes()
That one will read the whole file into the ByteArray. But you should carefully know you have enough RAM in the heap to do so
The ByteArray can be created via ByteArray(100) call, where 100 is the size of it
For the RandomAccessFile, it is probably better to use at the readFully function, which reads exactly the requested amount of bytes.
The classic approach is possible to read a file by chunks, e.g.
val buff = ByteArray(1230)
File("aaa").inputStream().buffered().use { input ->
while(true) {
val sz = input.read(buff)
if (sz <= 0) break
///at that point we have a sz bytes in the buff to process
consumeArray(buff, 0, sz)
}
}
I found this worked nicely:
fun File.chunkedSequence(chunk: Int): Sequence<ByteArray> {
val input = this.inputStream().buffered()
val buffer = ByteArray(chunk)
return generateSequence {
val red = input.read(buffer)
if (red >= 0) buffer.copyOf(red)
else {
input.close()
null
}
}
}
Use it like this.
file.chunkedSequence(CHUNK_SIZE).forEach {
// Do something with `it`
}
Not an exact match to your question but this is the question that came up when I was looking to chunk a file into a sequence of byte arrays.
I am making my first evolutionary sim while also learning Kotlin. I want to save the state of epochs (what happens in each simulation) and am making a binary encoding to help with efficiency. I want to write bytes to a file in a buffered fashion (write every 10kb or something).
I am trying to attack this by writing a ByteArray and tracking the number of bytes "added", and then writing and resetting when it hits the limit. This would require a conditional statement for every byte I write to the buffer though, I was wondering if this is naive?
Thanks in advance for any help!