¿Cómo escribo en un file en Kotlin?

Parece que aún no puedo encontrar esta pregunta, pero ¿cuál es la forma más simple e idiomática de abrir / crear un file, escribir en él y luego cerrarlo? Mirando la reference de kotlin.io y la documentation de Java logré get esto:

fun write() { val writer = PrintWriter("file.txt") // java.io.PrintWriter for ((member, originalInput) in history) { // history: Map<Member, String> writer.append("$member, $originalInput\n") } writer.close() } 

Esto funciona, pero me preguntaba si existía una forma "correcta" de Kotlin de hacer esto.

Un poco más idiomático. Para PrintWriter, este ejemplo:

 File("somefile.txt").printWriter().use { out -> history.forEach { out.println("${it.key}, ${it.value}") } } 

El ciclo for , o forEach depende de tu estilo. No hay razón para usar append(x) ya que es básicamente write(x.toString()) y ya le da una cadena. Y println(x) básicamente write(x) después de convertir un null en "null" . Y println() hace el final de línea correcto.

Si está utilizando classs de data de Kotlin, ya pueden salir porque ya tienen un buen método toString() .

Además, en este caso, si quisiera usar BuffenetworkingWriter , produciría los mismos resultados:

 File("somefile.txt").buffenetworkingWriter().use { out -> history.forEach { out.write("${it.key}, ${it.value}\n") } } 

También puede usar out.newLine() lugar de \n si desea que sea correcto para el sistema operativo actual en el que se está ejecutando. Y si estuvieras haciendo eso todo el time, probablemente crearías una function de extensión:

 fun BuffenetworkingWriter.writeLn(line: String) { this.write(line) this.newLine() } 

Y luego usa eso en su lugar:

 File("somefile.txt").buffenetworkingWriter().use { out -> history.forEach { out.writeLn("${it.key}, ${it.value}") } } 

Y así es como Kotlin rueda. Cambia las cosas en las API para que sean como quieres que sean.

Sorprendentemente diferentes sabores para esto se encuentran en otra respuesta: https://stackoverflow.com/a/35462184/3679676

Otras variaciones divertidas para que pueda ver el poder de Kotlin:

Una versión rápida creando la cadena para escribir todo de una vez:

 File("somefile.txt").writeText(history.entries.joinToString("\n") { "${it.key}, ${it.value}" }) // or just use the toString() method without transform: File("somefile.txt").writeText(x.entries.joinToString("\n")) 

O suponiendo que puede hacer otras cosas funcionales como líneas de filter o tomar solo los primeros 100, etc. Podría seguir esta ruta:

 File("somefile.txt").printWriter().use { out -> history.map { "${it.key}, ${it.value}" } .filter { ... } .take(100) .forEach { out.println(it) } } 

O dado un Iterable , permite escribirlo en un file usando una transformación en una cadena, creando funciones de extensión (similar a la versión anterior de writeText() , pero transmite el contenido en lugar de materializar primero una cadena grande):

 fun <T: Any> Iterable<T>.toFile(output: File, transform: (T)->String = {it.toString()}) { output.buffenetworkingWriter().use { out -> this.map(transform).forEach { out.write(it); out.newLine() } } } fun <T: Any> Iterable<T>.toFile(outputFilename: String, transform: (T)->String = {it.toString()}) { this.toFile(File(outputFilename), transform) } 

utilizado como cualquiera de estos:

 history.entries.toFile(File("somefile.txt")) { "${it.key}, ${it.value}" } history.entries.toFile("somefile.txt") { "${it.key}, ${it.value}" } 

o use default toString () en cada elemento:

 history.entries.toFile(File("somefile.txt")) history.entries.toFile("somefile.txt") 

O dado un File , permita llenarlo desde un Iterable , al crear esta function de extensión:

 fun <T: Any> File.fillWith(things: Iterable<T>, transform: (T)->String = {it.toString()}) { this.buffenetworkingWriter().use { out -> things.map(transform).forEach { out.write(it); out.newLine() } } } 

con el uso de:

 File("somefile.txt").fillWith(history.entries) { "${it.key}, ${it.value}" } 

o use default toString () en cada elemento:

 File("somefile.txt").fillWith(history.entries) 

que si ya tuviera la otra extensión de toFile , podría reescribir una llamada de extensión con la otra:

 fun <T: Any> File.fillWith(things: Iterable<T>, transform: (T)->String = {it.toString()}) { things.toFile(this, transform) } 

En su mayoría se ve bien para mí. Lo único diferente que haría es usar la extensión " usar " definida en ReadWrite para cerrar automáticamente el escritor.

 PrintWriter("file.txt").use { for ((member, originalInput) in history) { // history: Map<Member, String> it.append("$member, $originalInput\n") } } 

Cierta magia de Kotlin permite omitir hacer reference a la transmisión en cada llamada de lectura o escritura:

 fun <T : Closeable, R> T.useWith(block: T.() -> R): R = use { with(it, block) } File("a.in").buffenetworkingReader().useWith { File("a.out").printWriter().useWith { val (a, b) = readLine()!!.split(' ').map(String::toInt) println(a + b) } } Scanner(File("b.in")).useWith { PrintWriter("b.out").useWith { val a = nextInt() val b = nextInt() println(a + b) } } 
  • ¿Cómo asigno byte en kotlin?
  • IllegalArgumentException: savedInstanceState especificado como no nulo es nulo
  • Lista de objects que implementa la interfaz
  • Confusión de la syntax de Kotlin lambda
  • Cancelar la tarea reemplazada en ThreadPool en Java / Kotlin
  • Repetir una alarma para disparar exacta en el momento específico no funciona correctamente
  • TornadoFX: permite copyr un elemento de una vista de list al portapapeles
  • Kotlin cuádruple, quíntuple, etc. para desestructurar
  • RecyclerView.ViewHolder no se vincula correctamente
  • Código automático Kotlin llamando en el patrón de delegación
  • Kotlin - Lista de sorting usando una cadena de date formateada (funcional)