Something is wrong with my code that works with Fi...
# getting-started
n
Something is wrong with my code that works with File IO.
Copy code
fun main() {
    val strs = listOf(
        "line1",
        "line2"
    )
    val writer = File("src/main/resources/logging/temp.txt")
        .writer()

    strs.forEach { writer.appendLine(it) }
    writer.close()
}
The
temp.txt
file is empty when I run this program. After that the contents of the
temp.txt
file looks something like this,
Copy code
line1
line2
This is a perfectly reasonable output. However, things go wrong when I run a slightly modified version of the code for the second time.
Copy code
fun main() {
    val strs = listOf(
        "line3",
        "line4"
    )
    val writer = File("src/main/resources/logging/temp.txt")
        .writer()

    strs.forEach { writer.appendLine(it) }
    writer.close()
}
This is the new version. But this time the
temp.txt
file wasn't empty. It had the output of the first program saved into it. However, after running the new version the
temp.txt
file looks like this,
Copy code
line3
line4
The contents written by the first program are completely wiped out. Isn't the
temp.txt
file supposed to look like this?
Copy code
line1
line2
line3
line4
If not then what's even the point of using
append
over
write
? Isn't
append
expected to write new content after the previously added content instead of wiping out and starting afresh? Or, am I missing something?
k
What is happening is that you're calling the
writer()
extension to
java.io.File
. This extension creates a new
java.io.FileWriter
which it constructs without the
append
argument, so that this FileWriter truncates the file. The
append
method you're calling comes from the FileWriter's
Appendable
interface - nothing to do with appending to the file.
n
@Klitos Kyriacou I see. But what is a proper way of appending to a text file?
p
One of many options is to create your writer with
StandardOpenOption.APPEND
as an `OpenOption`:
Copy code
val writer = Path("C:/Users/pgriffith/Downloads/test.txt")
    .writer(options = arrayOf(StandardOpenOption.APPEND))
n
@Paul Griffith That seems a reasonable way to do that. But it feels kind of java-ish. Is there any idiomatic way to do it in Kotlin?
t
Well... Isn't Kotlin java-ish itself? ^^
😅 1
e
these IO extensions are Java-only to begin with…
p
Kotlin doesn't have multiplatform file IO (yet), so you're going to be calling a Java API to read a file no matter what. The
writer
extension is already significantly nicer than the
Files
static method you'd use in plain Java
e
you can define your own with an
append: Boolean
parameter
also, you should probably use
.use { }
(equivalent to try-with-resources in Java) to auto-close at the end of the block, and consider using
.buffered
p
Heh, actually, if you use Path you've actually already got an even nicer API -
path.appendLines()
Copy code
public inline fun Path.appendLines(lines: Iterable<CharSequence>, charset: Charset = Charsets.UTF_8): Path {
for more explicit use of a buffered writer if this is going to end up a large file/you're writing many lines, though