Is something wrong with my code here(doing java.io...
# coroutines
o
Is something wrong with my code here(doing java.io.File writing in a coroutine)
Copy code
class AsyncLogger : AbstractLogger {

    constructor(filepath: String,name: String) : super() {
        var file = File(filepath)
        file.mkdirs()
        filename = "$filepath/$name"
        file = File(filename)
    }

    suspend fun log(toLog: Boolean,msg: String) = coroutineScope {
        GlobalScope.launch {
            if (toLog)
                writeToFile(msg)
        }
    }

    suspend fun log(toLog: Boolean,toFile: Boolean,msg: String) = coroutineScope {
        GlobalScope.launch {
            if(toLog)
                when(toFile) {
                    true -> writeToFile(msg)
                    false -> writeToFile(msg)
                }
        }
    }

    override suspend fun writeToSTDOUT(msg: String) =
            println(message = "[${Thread.currentThread().name}]: $msg")

    override suspend fun writeToFile(msg: String): Job = coroutineScope {
        GlobalScope.launch {
            val stream = RandomAccessFile(filename, "rw")
            val channel = stream.channel
            var lock: FileLock? = null
            try {
                lock = channel.tryLock()
            } catch (e: OverlappingFileLockException) {
                stream.close()
                channel.close()
            }
            stream.writeBytes(msg + '\n')
            lock?.release()
            stream.close()
            channel.close()
        }
    }

}
Getting this error;
Copy code
Exception in thread "DefaultDispatcher-worker-2" java.io.IOException: Stream Closed
	at java.io.RandomAccessFile.writeBytes(Native Method)
	at java.io.RandomAccessFile.writeBytes(RandomAccessFile.java:1100)
	at com.github.otakusenpai.aghora.commonUtils.log.AsyncLogger$writeToFile$2$1.doResume(AsyncLogger.kt:50)
	at kotlin.coroutines.experimental.jvm.internal.CoroutineImpl.resume(CoroutineImpl.kt:54)
	at kotlinx.coroutines.experimental.DispatchedTask$DefaultImpls.run(Dispatched.kt:168)
	at kotlinx.coroutines.experimental.DispatchedContinuation.run(Dispatched.kt:13)
	at kotlinx.coroutines.experimental.scheduling.Task.run(Tasks.kt:94)
	at kotlinx.coroutines.experimental.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:583)
	at kotlinx.coroutines.experimental.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
	at kotlinx.coroutines.experimental.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:729)
at here
Copy code
stream.close()
n
m guess is that you are still doing work on the stream, but since you just launch and do not wait it closes it while still working on it.. where that code is.. i do no know on first glance
o
so should i do a runBlocking call ?
n
i have honestly no cle if that would be better
o
hmm thnx anyways
h
with
use {}
you don't have to bother about closing the streams yourself ...
o
hmm thnx
a
Think locking a file on every write operation is a bad idea. Such a writer can be implemented using an actor:
Copy code
override suspend fun writeToFile(msg: String) = scope.actor<String> {
    for (msg in this) {
        stream.writeBytes("$msg\n")
    }
}
And inside
log
function you can just send message into the channel.
There can be single
log
function:
Copy code
suspend fun log(msg: String, toLog: Boolean, toFile: Boolean = false)
Possibly it is worth to combine
toLog
&
toFile
arguments into an enum.
Coroutine
scope
can be passed via constructor, so you will be able to define the scope from the outside.