假设我正在阅读InputStream
。
我通常如何做到这一点:
val inputStream = ...
try {
doStuff(inputStream)
} finally {
inputStream.close()
}
doStuff
是否会引发异常,我们会关闭InputStream
。
我将如何使用iteratees:
val inputStream ...
Enumerator.fromStream(inputStream)(Iteratee.foreach(doStuff))
InputStream
是否会被关闭(即使doStuff
会引发异常)?
一点点测试:
val inputStream = new InputStream() { // returns 10, 9, ... 0, -1
private var i = 10
def read() = {
i = math.max(0, i) - 1
i
}
override def close() = println("closed") // looking for this
}
Enumerator.fromStream(inputStream)(Iteratee.foreach(a => 1 / 0)).onComplete(println)
我们只看到:
Failure(java.lang.ArithmeticException: / by zero)
流从未关闭过。将1 / 0
替换为1 / 1
,您会看到该流已关闭。
当然,我可以保留对原始流的引用并在发生故障时关闭它,但AFAIK使用iteratees的想法是创建可组合迭代而不必这样做。
这是预期的行为吗?
有没有办法使用iteratees,所以资源总是正确处理?
答案 0 :(得分:2)
Iteratees专为安全资源管理而设计。请参阅 Iteratee IO: safe, practical, declarative input processing 的第一句话:
Iteratee IO是一种增量输入处理方式,具有精确的资源控制。
这个想法是,当你的资源只能通过iteratees访问时,拥有资源的代码可以准确地告诉iteratee何时完成资源并立即关闭它。另一方面,当手动管理迭代时(与传统的InputStream
一样),资源的用户负责关闭它。这可能导致泄漏。
说,Play 2.1中有一个错误fromStream
没有管理其底层InputStream
的关闭!这个错误已在Play 2.2中修复。
您可以看到fromStream
code,以便在迭代完成后使用Enumerator
关闭资源来查看onDoneEnumerating
是如何修复的。