我如何写入 Kotlin 中的文件?
How do I write to a file in Kotlin?
我似乎还找不到这个问题,但是 opening/creating 文件、写入文件然后关闭它的最简单、最惯用的方法是什么?查看 kotlin.io 参考资料和 Java 文档,我设法得到了这个:
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()
}
这行得通,但我想知道是否有 "proper" Kotlin 方法可以做到这一点?
我觉得大部分都还不错。我唯一不同的是使用 ReadWrite 中定义的“use”扩展来自动关闭编写器。
PrintWriter("file.txt").use {
for ((member, originalInput) in history) { // history: Map<Member, String>
it.append("$member, $originalInput\n")
}
}
更地道一点。对于 PrintWriter,此示例:
File("somefile.txt").printWriter().use { out ->
history.forEach {
out.println("${it.key}, ${it.value}")
}
}
for
循环或 forEach
取决于您的风格。没有理由使用 append(x)
因为它基本上是 write(x.toString())
并且你已经给它一个字符串。而 println(x)
在将 null
转换为 "null"
之后基本上会执行 write(x)
。 println()
行结尾正确。
如果你使用的是 Kotlin 的 data
类,它们已经可以输出了,因为它们已经有了一个很好的 toString()
方法。
此外,在这种情况下,如果您想使用 BufferedWriter
,它会产生相同的结果:
File("somefile.txt").bufferedWriter().use { out ->
history.forEach {
out.write("${it.key}, ${it.value}\n")
}
}
您也可以使用 out.newLine()
而不是 \n
,如果您希望它在当前操作系统中是正确的 运行。如果你一直这样做,你可能会创建一个扩展函数:
fun BufferedWriter.writeLn(line: String) {
this.write(line)
this.newLine()
}
然后改用它:
File("somefile.txt").bufferedWriter().use { out ->
history.forEach {
out.writeLn("${it.key}, ${it.value}")
}
}
这就是 Kotlin 的发展方向。改变 API 中的内容,使它们成为您想要的样子。
另一个答案对此有截然不同的口味:
其他有趣的变体让您看到 Kotlin 的强大功能:
通过创建字符串来一次性写入的快速版本:
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"))
或者假设您可能会做其他功能性的事情,例如过滤行或只取前 100 条等。您可以走这条路:
File("somefile.txt").printWriter().use { out ->
history.map { "${it.key}, ${it.value}" }
.filter { ... }
.take(100)
.forEach { out.println(it) }
}
或者给定一个 Iterable
,允许通过创建扩展函数(类似于 writeText()
版本)使用字符串转换将其写入文件上面,但流式传输内容而不是首先具体化一个大字符串):
fun <T: Any> Iterable<T>.toFile(output: File, transform: (T)->String = {it.toString()}) {
output.bufferedWriter().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)
}
用作以下任何一项:
history.entries.toFile(File("somefile.txt")) { "${it.key}, ${it.value}" }
history.entries.toFile("somefile.txt") { "${it.key}, ${it.value}" }
或在每个项目上使用默认的 toString():
history.entries.toFile(File("somefile.txt"))
history.entries.toFile("somefile.txt")
或者给定一个 File
,允许从 Iterable
填充它,方法是创建此扩展函数:
fun <T: Any> File.fillWith(things: Iterable<T>, transform: (T)->String = {it.toString()}) {
this.bufferedWriter().use { out ->
things.map(transform).forEach { out.write(it); out.newLine() }
}
}
使用:
File("somefile.txt").fillWith(history.entries) { "${it.key}, ${it.value}" }
或在每个项目上使用默认的 toString():
File("somefile.txt").fillWith(history.entries)
如果您已经有另一个 toFile
分机,您可以重写让一个分机调用另一个分机:
fun <T: Any> File.fillWith(things: Iterable<T>, transform: (T)->String = {it.toString()}) {
things.toFile(this, transform)
}
一些 Kotlin 魔法允许在每次读取或写入调用时省略对流的引用:
fun <T : Closeable, R> T.useWith(block: T.() -> R): R = use { with(it, block) }
File("a.in").bufferedReader().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)
}
}
try{
val fileWriter = FileWriter("test.txt", true)
fileWriter.write(string+ "\n")
fileWriter.close()
} catch (exception: Exception){
println(exception.message)
}
至少,您可以使用:
FileWriter(filename).use { it.write(text) }
FileWriter 是编写字符文件的便利 class(由 Java 提供,因此在 Kotlin 中可用)。它扩展了 Closeable,因此可以被 Kotlin 的“.use”扩展方法使用。
一旦块退出,.use 扩展方法会自动关闭调用对象,从而提供一种在文件写入后关闭文件的惯用方法。
示例很简单
val path = context!!.filesDir.absolutePath // => /data/user/0/com.example.test/files
File("$path/filename.txt").writeText("hello")
我似乎还找不到这个问题,但是 opening/creating 文件、写入文件然后关闭它的最简单、最惯用的方法是什么?查看 kotlin.io 参考资料和 Java 文档,我设法得到了这个:
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()
}
这行得通,但我想知道是否有 "proper" Kotlin 方法可以做到这一点?
我觉得大部分都还不错。我唯一不同的是使用 ReadWrite 中定义的“use”扩展来自动关闭编写器。
PrintWriter("file.txt").use {
for ((member, originalInput) in history) { // history: Map<Member, String>
it.append("$member, $originalInput\n")
}
}
更地道一点。对于 PrintWriter,此示例:
File("somefile.txt").printWriter().use { out ->
history.forEach {
out.println("${it.key}, ${it.value}")
}
}
for
循环或 forEach
取决于您的风格。没有理由使用 append(x)
因为它基本上是 write(x.toString())
并且你已经给它一个字符串。而 println(x)
在将 null
转换为 "null"
之后基本上会执行 write(x)
。 println()
行结尾正确。
如果你使用的是 Kotlin 的 data
类,它们已经可以输出了,因为它们已经有了一个很好的 toString()
方法。
此外,在这种情况下,如果您想使用 BufferedWriter
,它会产生相同的结果:
File("somefile.txt").bufferedWriter().use { out ->
history.forEach {
out.write("${it.key}, ${it.value}\n")
}
}
您也可以使用 out.newLine()
而不是 \n
,如果您希望它在当前操作系统中是正确的 运行。如果你一直这样做,你可能会创建一个扩展函数:
fun BufferedWriter.writeLn(line: String) {
this.write(line)
this.newLine()
}
然后改用它:
File("somefile.txt").bufferedWriter().use { out ->
history.forEach {
out.writeLn("${it.key}, ${it.value}")
}
}
这就是 Kotlin 的发展方向。改变 API 中的内容,使它们成为您想要的样子。
另一个答案对此有截然不同的口味:
其他有趣的变体让您看到 Kotlin 的强大功能:
通过创建字符串来一次性写入的快速版本:
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"))
或者假设您可能会做其他功能性的事情,例如过滤行或只取前 100 条等。您可以走这条路:
File("somefile.txt").printWriter().use { out ->
history.map { "${it.key}, ${it.value}" }
.filter { ... }
.take(100)
.forEach { out.println(it) }
}
或者给定一个 Iterable
,允许通过创建扩展函数(类似于 writeText()
版本)使用字符串转换将其写入文件上面,但流式传输内容而不是首先具体化一个大字符串):
fun <T: Any> Iterable<T>.toFile(output: File, transform: (T)->String = {it.toString()}) {
output.bufferedWriter().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)
}
用作以下任何一项:
history.entries.toFile(File("somefile.txt")) { "${it.key}, ${it.value}" }
history.entries.toFile("somefile.txt") { "${it.key}, ${it.value}" }
或在每个项目上使用默认的 toString():
history.entries.toFile(File("somefile.txt"))
history.entries.toFile("somefile.txt")
或者给定一个 File
,允许从 Iterable
填充它,方法是创建此扩展函数:
fun <T: Any> File.fillWith(things: Iterable<T>, transform: (T)->String = {it.toString()}) {
this.bufferedWriter().use { out ->
things.map(transform).forEach { out.write(it); out.newLine() }
}
}
使用:
File("somefile.txt").fillWith(history.entries) { "${it.key}, ${it.value}" }
或在每个项目上使用默认的 toString():
File("somefile.txt").fillWith(history.entries)
如果您已经有另一个 toFile
分机,您可以重写让一个分机调用另一个分机:
fun <T: Any> File.fillWith(things: Iterable<T>, transform: (T)->String = {it.toString()}) {
things.toFile(this, transform)
}
一些 Kotlin 魔法允许在每次读取或写入调用时省略对流的引用:
fun <T : Closeable, R> T.useWith(block: T.() -> R): R = use { with(it, block) }
File("a.in").bufferedReader().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)
}
}
try{
val fileWriter = FileWriter("test.txt", true)
fileWriter.write(string+ "\n")
fileWriter.close()
} catch (exception: Exception){
println(exception.message)
}
至少,您可以使用:
FileWriter(filename).use { it.write(text) }
FileWriter 是编写字符文件的便利 class(由 Java 提供,因此在 Kotlin 中可用)。它扩展了 Closeable,因此可以被 Kotlin 的“.use”扩展方法使用。
一旦块退出,.use 扩展方法会自动关闭调用对象,从而提供一种在文件写入后关闭文件的惯用方法。
示例很简单
val path = context!!.filesDir.absolutePath // => /data/user/0/com.example.test/files
File("$path/filename.txt").writeText("hello")