Both File.bufferedWriter and File.printWriter actually rewrite the target file, replacing its content with what you write with them. This is mostly equivalent to what would happen if you used f.writeText(...), not f.appendText(...).
One solution would be to create a FileOutputStream in the append mode by using the appropriate constructor FileOutputStream(file: File, append: Boolean), for example:
FileOutputStream(f, true).bufferedWriter().use { writer ->
//...
}
Answer from hotkey on Stack OverflowBoth File.bufferedWriter and File.printWriter actually rewrite the target file, replacing its content with what you write with them. This is mostly equivalent to what would happen if you used f.writeText(...), not f.appendText(...).
One solution would be to create a FileOutputStream in the append mode by using the appropriate constructor FileOutputStream(file: File, append: Boolean), for example:
FileOutputStream(f, true).bufferedWriter().use { writer ->
//...
}
For what it is worth, I ended up using the following based on a combination of suggestions including the one from "hotkey". I needed for the append to be conditional including a newline to prepare for any future contents.
FileOutputStream(File(fileNameAndPath), isAppendMode).bufferedWriter().use {
writer -> writer.write(textToWrite)
if (isAppendMode) { writer.newLine() }
}
It appears there are many ways to create a file and append to it, depending on the minimum API version you are developing for. I am using minimum Android API 22. The code to create/append a file is below:
val HEADER = "DATE,NAME,AMOUNT_DUE,AMOUNT_PAID"
var filename = "export.csv"
var path = getExternalFilesDir(null) //get file directory for this package
//(Android/data/.../files | ... is your app package)
//create fileOut object
var fileOut = File(path, filename)
//delete any file object with path and filename that already exists
fileOut.delete()
//create a new file
fileOut.createNewFile()
//append the header and a newline
fileOut.appendText(HEADER)
fileOut.appendText("\n")
/*
write other data to file
*/
I cannot find the file in the file system
Use Android Studio's Device File Explorer and look in /data/data/.../files/, where ... is your application ID.
Also, you can write your code a bit more concisely as:
try {
PrintWriter(openFileOutput(filename,Context.MODE_PRIVATE)).use {
it.println(HEADER)
}
} catch(e: Exception) {
Log.e("TAG", e.toString())
}
use() will automatically close the PrintWriter, and PrintWriter gives you a more natural API for writing out text.
You can just jump into the implementation of appendText in your IDE to find out (Ctrl + B on Windows, ⌘B on Mac).
Here's the implementation of the method:
public fun File.appendText(text: String, charset: Charset = Charsets.UTF_8): Unit
= appendBytes(text.toByteArray(charset))
And here's the appendBytes method that it delegates the work to:
public fun File.appendBytes(array: ByteArray): Unit
= FileOutputStream(this, true).use { it.write(array) }
You can see that it actually uses the use helper method as you've expected.
You are right there is no appendText function on Writer, you can see here as further.
The use function is same as java-7 try-with-resource expression. it will close the resource after the block exit. In fact, File#appendText call the use function to close the resource.
IF you append the text only once you can using File#appendText instead. for example:
out8.appendText("content")
IF you want to operate a file more than once, you should using the File#bufferedWriter() instead, since the File#appendText will create & open a new writer each time. for example:
out8.bufferedWriter().use{
it.append("first").append("second")
}