File Channel
An AsynchronousFileChannel
provides an API for handling files in a non-blocking way.
Required imports for presented snippets:
import zio._
import zio.nio.channels._
import zio.nio.file._
import zio.Console._
Basic operations
Opening a file for a given path (with no additional open attributes) returns a scoped ZIO
instance on which we're running the intended operations. Scope
makes sure that the channel gets closed afterwards:
import java.nio.file.StandardOpenOption
val path = Path("file.txt")
val channelM = ZIO.scoped {
AsynchronousFileChannel.open(
path,
StandardOpenOption.READ,
StandardOpenOption.WRITE
).flatMap { channel =>
readWriteOp(channel) *> lockOp(channel)
}
}
Reading and writing is performed as effects where raw Byte
content is wrapped in Chunk
:
val readWriteOp = (channel: AsynchronousFileChannel) =>
for {
chunk <- channel.readChunk(20, 0L)
text = chunk.map(_.toChar).mkString
_ <- printLine(text)
input = Chunk.fromArray("message".toArray.map(_.toByte))
_ <- channel.writeChunk(input, 0L)
} yield ()
Contrary to previous operations, file locks are performed with the core java.nio.channels.FileLock
class so
they are not in effects. Apart from basic acquire/release actions, the core API offers, among other things, partial locks and overlap checks:
val lockOp = (channel: AsynchronousFileChannel) =>
for {
isShared <- ZIO.acquireReleaseWith(channel.lock())(_.release.ignore)(l => ZIO.succeed(l.isShared))
_ <- printLine(isShared.toString) // false
scoped = ZIO.acquireRelease(channel.lock(position = 0, size = 10, shared = false))(_.release.ignore)
isOverlaping <- ZIO.scoped(scoped.flatMap(l => ZIO.succeed(l.overlaps(5, 20))))
_ <- printLine(isOverlaping.toString) // true
} yield ()
Also it's worth mentioning that we are treating FileLock
as a resource here.
For demonstration purposes we handled it in two different ways: using acquireRelease
and creating a scoped ZIO
for this.