Lendo arquivos com o Kotlin
Entendendo as técnicas de IO
Ao escrever um programa, é natural apresentarmos informações para quem utilizará, como por exemplo, quando imprimimos uma mensagem no console.
Porém, além de apresentar uma mensagem, também somos capazes de ler informações deste usuário ou usuária, ou até mesmo ler arquivos e escrever nos mesmos.
E essas técnicas em desenvolvimento de software, são conhecidas como IO - Input Output ou entrada e saída.
Como funcionam as técnicas de IO no Kotlin?
Por utilizar o ambiente da JVM, o Kotlin reutiliza toda estrutura de IO da linguagem Java, portanto, se você já está familiarizado com Java, assim como vemos no curso de java.io, você pode usar as mesmas técnicas que o seu programa funcionará sem problemas!
"Então qual é a diferença no Kotlin?"
A grande sacada do Kotlin é facilitar mais ainda a maneira como lidamos com o IO a partir de funções extensão.
Lendo arquivos em Java
Temos várias opções ao ler um arquivo em Java, como por exemplo: utilizando a classe Scanner
:
public class Leitor {
public void ler() {
File arquivo = new File("lista-desejos.txt");
try {
Scanner leitor = new Scanner(arquivo);
while(leitor.hasNext()){
System.out.println(leitor.next());
}
leitor.close();
} catch (FileNotFoundException e) {
System.out.println("Falha ao ler o arquivo");
e.printStackTrace();
}
}
}
Neste código, para que a leitura seja feita, precisamos:
- Acessar o arquivo via
File
; - Enviar o arquivo para o
Scanner
; - Pegar o conteúdo enquanto existe (e imprimir, por exemplo);
- Fechar o recurso.
Além da exigência do tratamento da exception, observe que temos um boilerplate quando precisamos ler um arquivo no Java. Podemos reduzir mais o código utilizando o try-catch-resources:
File arquivo = new File("lista-desejos.txt");
try(Scanner leitor = new Scanner(arquivo);) {
while(leitor.hasNext()){
System.out.println(leitor.next());
}
} catch (FileNotFoundException e) {
System.out.println("Falha ao ler o arquivo");
e.printStackTrace();
}
A partir desta técnica, não há necessidade de fechar o recurso explicitamente, pois ao usar essa instrução, qualquer referência que implemente [Closeable](https://docs.oracle.com/javase/8/docs/api/java/io/Closeable.html)
, como é o caso da Scanner
, tem o recurso fechado no final da instrução try
.
Note que ambos os códigos ainda não são tão atrativos pelos passos que precisamos fazer apenas para ler um arquivo.
Lendo arquivos com extensões do Kotlin
No Kotlin temos uma abordagem mais simplificada, a partir das extensões para File IO, entregamos o mesmo com apenas uma chamada de função, o forEachLine()
:
fun ler() {
try {
File("lista-desejos.txt").forEachLine { linha ->
println(linha)
}
} catch (e: FileNotFoundException) {
println("Falha ao ler o arquivo");
e.printStackTrace();
}
}
Ou até mesmo de uma maneira mais reduzida utilizando o method reference:
fun ler() {
try {
File("lista-desejos.txt").forEachLine(action = ::println)
} catch (e: FileNotFoundException) {
println("Falha ao ler o arquivo");
e.printStackTrace();
}
}
A princípio parece mágica, mas internamente a estratégia é a mesma do try-catch-resources.
A implementação de leitura padrão utiliza uma referência que implementa a interface Closeable
e fecha o recurso após a execução do forEachLine()
Utilizando a função use()
Além de usar as extensões de File
, também podemos fazer o mesmo código que vimos com o try-catch-resources a partir da função use()
, uma extensão de Closeable
para usar um recurso e fechá-lo automaticamente após o uso:
fun ler() {
val arquivo = File("lista-desejos.txt")
try {
Scanner(arquivo).use { leitor ->
while (leitor.hasNext()) {
println(leitor.next())
}
}
} catch (e: FileNotFoundException) {
println("Falha ao ler o arquivo")
e.printStackTrace()
}
}
Conclusão
Portanto, no Kotlin temos a opção de ler arquivos utilizando o modo mais simplificado, como por exemplo, o forEachLine()
, ou também, podemos utilizar qualquer membro da API de IO do Java que implemente a interface Closeable
a partir da função use()
.