我希望在Kotlin脚本中使用接收HTTP请求。
我只需要请求中的两行,所以我尝试将整个请求作为字符串行来获得,迭代它,并获得与这两行的regex匹配的行。
我用FileInputStream测试了一个文本文件,而不是从客户端发送的实际InputStream。我只能迭代一次,所以不能得到第二行。我收到以下结果。
获取/hello.html HTTP/1.1 线程"main“java.util.NoSuchElementException中的异常: Sequence不包含与谓词匹配的元素。在RequestParam$filterLines$1.invoke(RequestParam.kt:29) at RequestParam$filterLines$1.invoke(RequestParam.kt:6) at RequestParam.(RequestParam.kt:19) at RequestParamKt.main(RequestParam.kt:26)
官方的Kotlin引用说,由asSequence()实例化的序列不能重复一次以上。所以我使用了供应商界面,但这不起作用。
我以前也试过同样的方法而且成功了。我现在正在重写代码,因为以前的版本有点混乱。以前的版本是这里
下面是我正在苦苦挣扎的当前版本。
import java.io.FileInputStream
import java.io.InputStream
import java.util.function.Supplier
import kotlin.streams.asSequence
class RequestParam(private val inputStream: InputStream) {
val path: String
val host: String
init {
//I'd like to receive request from client as multiple lines of String.
//I generated Supplier since instance made by asSequence() cannot be iterated more than once https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/index.html
val linesSupplier: Supplier<Sequence<String>> = Supplier { inputStream.bufferedReader().lines().asSequence() }
//I only need lines starting with "GET" or "Host:"
val regex = { x: String -> { y: String -> y.matches(Regex(x)) } }
val regexGet = regex("GET.*")
val regexHost = regex("Host:.*")
//Iterate supplier and get the first line that matches each regex
val filterLines = { x: Sequence<String>, y: (String) -> Boolean -> x.first(y) }
path = filterLines(linesSupplier.get(), regexGet)
println(path) //works fine
host = filterLines(linesSupplier.get(), regexHost)
println(host) // no good
}
}
fun main(args: Array<String>) {
//Test with some file
val inputStream = FileInputStream("C:\\path\\to\\my\\test.txt")
val requestParam = RequestParam(inputStream)
}以及我在测试中使用的文本文件
GET /hello.html HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)
Host: www.barfoo.com
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive为什么我不能迭代linesSupplier不止一次?
发布于 2019-08-17 11:08:56
表示延迟计算的集合的序列类型。顶层函数用于实例化序列,扩展函数用于序列。
对于没有suplier的解决方案:正如文档所述,sequence试图惰性地计算由inputStream‘line’方法返回的流中的值。因此,对于第一个调用,它将读取流,第二个调用尝试执行相同的操作,这将失败,因为您不能读取该流两次。您可以使用toList而不是asSequence来解决这个问题。列表将只读一次,并将其保存在内存中。如果你不局限于记忆,它将解决你的问题。
val linesSupplier: List<String> = inputStream.bufferedReader().lines().toList()编辑:对于供应商的解决方案:您应该能够通过将文件流的创建移动到供应商来使其工作。在您的代码段中,供应商会失败,因为您使用的是已经使用的相同的流。
val linesSupplier: Supplier<Sequence<String>> = Supplier { FileInputStream("C:\\test.txt").bufferedReader().lines().asSequence() }发布于 2019-08-17 10:43:26
因为在第一次调用linesSupplier.get()时,您消耗了inputStream,而在第二次调用时,它会引发异常。与其使用供应商,不如定义一个正常的Sequence并使用它:
val lines: Sequence<String> = inputStream.bufferedReader().lines().asSequence()
//...
path = filterLines(lines, regexGet)
//...
host = filterLines(lines, regexHost)https://stackoverflow.com/questions/57535225
复制相似问题