You can simplify your function by using the copyTo function:
fun File.copyInputStreamToFile(inputStream: InputStream) {
this.outputStream().use { fileOut ->
inputStream.copyTo(fileOut)
}
}
Answer from yole on Stack OverflowYou can simplify your function by using the copyTo function:
fun File.copyInputStreamToFile(inputStream: InputStream) {
this.outputStream().use { fileOut ->
inputStream.copyTo(fileOut)
}
}
My proposition is:
fun InputStream.toFile(path: String) {
File(path).outputStream().use { this.copyTo(it) }
}
without closing current stream
InputStream.toFile("/path/filename")
also, do not forget to handle exceptions, for example if write permission is denied :)
Kotlin has a specific extension just for this purpose.
The simplest:
val inputAsString = input.bufferedReader().use { it.readText() } // defaults to UTF-8
And in this example, you could decide between bufferedReader() or just reader(). The call to the function Closeable.use() will automatically close the input at the end of the lambda's execution.
Further reading:
If you do this type of thing a lot, you could write this as an extension function:
fun InputStream.readTextAndClose(charset: Charset = Charsets.UTF_8): String {
return this.bufferedReader(charset).use { it.readText() }
}
Which you could then call easily as:
val inputAsString = input.readTextAndClose() // defaults to UTF-8
On a side note, all Kotlin extension functions that require knowing the charset already default to UTF-8, so if you require a different encoding you need to adjust the code above in calls to include encoding for reader(charset) or bufferedReader(charset).
Warning: You might see examples that are shorter:
val inputAsString = input.reader().readText()
But these do not close the stream. Make sure you check the API documentation for all of the IO functions you use to be sure which ones close and which do not. Usually, if they include the word use (such as useLines() or use()) they close the stream after. An exception is that File.readText() differs from Reader.readText() in that the former does not leave anything open and the latter does indeed require an explicit close.
See also: Kotlin IO related extension functions
【Method 1 | Manually Close Stream】
private fun getFileText(uri: Uri):String {
val inputStream = contentResolver.openInputStream(uri)!!
val bytes = inputStream.readBytes() //see below
val text = String(bytes, StandardCharsets.UTF_8) //specify charset
inputStream.close()
return text
}
inputStream.readBytes()requires manually close the stream: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/java.io.-input-stream/read-bytes.html
【Method 2 | Automatically Close Stream】
private fun getFileText(uri: Uri): String {
return contentResolver.openInputStream(uri)!!.bufferedReader().use {it.readText() }
}
You can specify the charset inside
bufferedReader(), default isUTF-8: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/java.io.-input-stream/buffered-reader.htmlbufferedReader()is an upgrade version ofreader(), it is more versatile: How exactly does bufferedReader() work in Kotlin?use()can automatically close the stream when the block is done: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/use.html
Using "externalCacheDir" instead of "cacheDir" while creating file might solve the problem.
requireContext().externalCacheDir?.let {
val file = File(
it.path,
requireContext().contentResolver.getFileName(uri!!)
)
file.createNewFile()
}
Sending image to php server using Okhttp: First covert all images to byte array and put it in "backupData" list. Then call "backupOneByOne()" method.
private var client: OkHttpClient = OkHttpClient()
init {
client.setReadTimeout(5, TimeUnit.MINUTES)
client.setConnectTimeout(5, TimeUnit.MINUTES)
}
val backupData: MutableList<ByteArray> = mutableListOf()
private suspend fun backupOneByOne(currentPosition: Int, byteArray: ByteArray) {
val backupResponse = doBackupMultiPartData("merchantKey", byteArray)
when (backupResponse) {
is ResponseResult.Success -> {
Log.d("nm==>>", "Menu Item backup successful !!! AND current item position= $currentPosition")
if (currentPosition < backupData.size - 1) {
backupOneByOne(currentPosition + 1, backupData[currentPosition + 1])
} else {
Log.d("nm==>>", "Backup of all items is done. Current position= $currentPosition")
}
}
is ResponseResult.Error -> {
Log.d("nm==>>", "Error while backup of Advance table : \n ${backupResponse.msg.errorMsg}")
}
else -> {
}
}
}
suspend fun doBackupMultiPartData(apiKey: String, imageData: ByteArray?): ResponseResult<ResponseWrapper<String>> {
val requestBody = MultipartBuilder().type(MultipartBuilder.FORM)
//requestBody.addFormDataPart("id",2) put other form data fields
if (imageData != null) {
requestBody.addFormDataPart(
"file", "Logo.png", RequestBody.create(
MediaType.parse(
"image/png"
), imageData
)
)
}
val request = Request.Builder()
.header("api_key", apiKey) // getting api key from backend
.url("put url here....")
.post(requestBody.build())
.build()
try {
val result = apiRequest(request)
Log.d("nm==>>", "Result: $result")
return if (result != null) {
val jsonObject = JSONObject(result)
if (jsonObject.getBoolean("isSuccessful")) {
ResponseResult.Success(ResponseWrapper("success", null))
} else {
ResponseResult.Error(
ResponseWrapper(null, "Back end code error: \n $result")
)
}
} else {
ResponseResult.Error(
ResponseWrapper(
null, "Getting NULL as result"
)
)
}
} catch (jsonException: JSONException) {
Log.d("nm==>>", "Restore JSON exception::: \n ${jsonException.localizedMessage}")
return ResponseResult.Error(
ResponseWrapper(
null,
"Restore Json Exception"
)
)
} catch (exception: Throwable) {
//Log.d("nm==>>", "Network exception::: \n ${exception.localizedMessage}")
return ResponseResult.NoInternet
}
}
private suspend fun apiRequest(request: Request): String? = suspendCancellableCoroutine { cancellableContinuation ->
client.newCall(request).enqueue(object : Callback {
override fun onFailure(request: Request?, e: IOException?) {
cancellableContinuation.resumeWith(Result.failure(Throwable("API failed.....${e?.localizedMessage}")))
}
override fun onResponse(response: Response?) {
cancellableContinuation.resumeWith(Result.success(response?.body()?.string()))
}
})
}
sealed class ResponseResult<out T> {
object Loading:ResponseResult<Nothing>()
object Empty:ResponseResult<Nothing>()
data class Success<T>(val result:T): ResponseResult<T>()
data class Error<T>(val msg:T): ResponseResult<T>()
object NoInternet:ResponseResult<Nothing>()
}
data class ResponseWrapper<out T>(val data: T?, val errorMsg: String?)