我正在尝试创建一个将流写入分段文件的接收器:当达到特定条件(时间,文件大小等)时,关闭当前输出流并打开一个新流到一个新的存储桶文件。
我检查了如何在io
对象中创建不同的接收器,但是没有很多示例。因此,我想要了解resource
和chunkW
的编写方式。我最后得到了下面的一些代码,为简单起见,现在只用Int
代表桶,但最终会是某些类型的输出流。
val buckets: Channel[Task, String, Int] = {
//recursion to step through the stream
def go(step: Task[String => Task[Int]]): Process[Task, String => Task[Int]] = {
// Emit the value and repeat
def next(msg: String => Task[Int]) =
Process.emit(msg) ++
go(step)
Process.await[Task, String => Task[Int], String => Task[Int]](step)(
next
, Process.halt // TODO ???
, Process.halt) // TODO ???
}
//starting bucket
val acquire: Task[Int] = Task.delay {
val startBuck = nextBucket(0)
println(s"opening bucket $startBuck")
startBuck
}
//the write step
def step(os: Int): Task[String => Task[Int]] =
Task.now((msg: String) => Task.delay {
write(os, msg)
val newBuck = nextBucket(os)
if (newBuck != os) {
println(s"closing bucket $os")
println(s"opening bucket $newBuck")
}
newBuck
})
//start the Channel
Process.await(acquire)(
buck => go(step(buck))
, Process.halt, Process.halt)
}
def write(bucket: Int, msg: String) { println(s"$bucket\t$msg") }
def nextBucket(b: Int) = b+1
这里有很多问题:
step
在开始时传递一次桶,这在递归过程中永远不会改变。我不确定在递归go
中如何创建一个新的step
任务,该任务将使用前一个任务中的bucket(Int),因为我必须提供一个String来完成该任务。 / LI>
fallback
次调用的cleanup
和await
未收到rcv
的结果(如果有的话)。在io.resource
函数中,它在资源修复时工作正常,但在我的情况下,资源可能在任何步骤都会发生变化。我如何将对当前打开的存储桶的引用传递给这些回调?答案 0 :(得分:0)
其中一个选项(即时间)可能是在接收器上使用简单的go
。这个使用基于时间的,基本上每小时重新打开文件:
val metronome = Process.awakeEvery(1.hour).map(true)
def writeFileSink(file:String):Sink[Task,ByteVector] = ???
def timeBasedSink(prefix:String) = {
def go(index:Int) : Sink[Task,ByteVector] = {
metronome.wye(write(prefix + "_" + index))(wye.interrupt) ++ go(index + 1)
}
go(0)
}
对于其他选项(即写入的字节),您可以使用类似的技术,只需保持写入的字节信号并将其与Sink结合使用。