InputStream para String no Kotlin
1. Visão geral
Neste breve tutorial, descobriremos como ler umInputStream em umString.
Kotlin fornece uma maneira fácil de realizar a conversão. No entanto, ainda existem algumas nuances a serem consideradas ao trabalhar com recursos. Além disso, cobriremos casos especiais, comoreading up to a stop character.
2. Leitor em buffer
InputStream is an abstraction around an ordered stream of bytes. Uma fonte de dados subjacente pode ser um arquivo, uma conexão de rede ou qualquer outra fonte que emita bytes. Vamos usar um arquivo simples que contém os seguintes dados:
Computer programming can be a hassle
It's like trying to take a defended castle
A primeira solução que podemos tentar éread the file manualmente linha por linha:
val reader = BufferedReader(inputStream.reader())
val content = StringBuilder()
try {
var line = reader.readLine()
while (line != null) {
content.append(line)
line = reader.readLine()
}
} finally {
reader.close()
}
Primeiro, usamos a classeBufferedReader para embrulhar a areiaInputStream e depois lemos até que não haja mais linhas no fluxo. Além disso, cercamos a lógica de leitura pela instruçãotry-finally parafinally close the stream. Ao todo, há muito código clichê.
Poderíamos torná-lo mais compacto e legível?
Absolutamente! A princípio, podemos simplificar o snippet usando a funçãoreadText(). Ele lê o fluxo de entrada completamente como umString. Dessa forma, podemos refatorar nosso snippet da seguinte maneira:
val reader = BufferedReader(inputStream.reader())
var content: String
try {
content = reader.readText()
} finally {
reader.close()
}
No entanto, ainda temos aquele blocotry-finally. Felizmente, o Kotlin permite manipularresource management de uma maneira pseudo-automática. Vejamos as próximas linhas de código:
val content = inputStream.bufferedReader().use(BufferedReader::readText)
assertEquals(fileFullContent, content)
Essa solução de uma linha parece simples, no entanto, muita coisa está acontecendo sob o capô. Um ponto importante no código acima é a chamada da funçãouse(). Esteextension function executa um bloco em um recurso que implementa a interfaceClosable. Finalmente, quando o bloco é executadoKotlin closes the resource for us.
3. Caractere de parada
Ao mesmo tempo, pode haver um caso em que precisamosread content up to a specific character. Vamos definir uma função de extensão para a classeInputStream:
fun InputStream.readUpToChar(stopChar: Char): String {
val stringBuilder = StringBuilder()
var currentChar = this.read().toChar()
while (currentChar != stopChar) {
stringBuilder.append(currentChar)
currentChar = this.read().toChar()
if (this.available() <= 0) {
stringBuilder.append(currentChar)
break
}
}
return stringBuilder.toString()
}
This function reads bytes from an input stream until a stop character appears. Ao mesmo tempo, peçato prevent the infinite loop, we call the available() method para verificar se o fluxo tem dados restantes. Portanto, se não houver um caractere de parada em um fluxo, um fluxo inteiro será lido.
Por outro lado, nem todas as subclasses da classeInputStream fornecem uma implementação para o métodoavailable(). Consequentemente, temos que garantir que o método seja implementado corretamente antes de usar a função de extensão.
Vamos voltar ao nosso exemplo eread text up to the first whitespace character (‘‘):
val content = inputStream.use { it.readUpToChar(' ') }
assertEquals("Computer", content)
Como resultado, vamos levar o texto até o caractere de parada. Da mesma forma, não se esqueça dewrap the block with the use() function to automatically close the stream.
4. Conclusão
Neste artigo, vimos como converter umInputStream em umString em Kotlin. Kotlin fornece uma maneira concisa de trabalhar com fluxos de dados, mas sempre vale a pena saber o que está acontecendo internamente.
Como de costume, a implementação de todos esses exemplos éover on Github.