0

I want to write to a file periodically and always replace it if already exists. The problem is that, using MediaStore, instead of overwriting the file, it creates a new one with the same name and appends a number to it

fun exportToFile(fileName: String, content: String) {
    // save to downloads folder
    val contentValues = ContentValues().apply {
        put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
        put(MediaStore.MediaColumns.MIME_TYPE, "text/plain")
        put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
    }

    val extVolumeUri: Uri = MediaStore.Files.getContentUri("external")
    val fileUri = context.contentResolver.insert(extVolumeUri, contentValues)

    // save file
    if (fileUri != null) {
        val os = context.contentResolver.openOutputStream(fileUri, "wt")

        if (os != null) {
            os.write(content.toByteArray())
            os.close()
        }
    }
}

If I call exportToFile("test.txt", "Hello world"), it writes a file test.txt. If I call the same function again, it creates a new one called test(1).txt in the same folder. How do I override this and make it write to the same file?

alexmro
  • 563
  • 4
  • 16
  • 1
    Perhaps you should not be using `MediaStore`, especially for a text file. Even if you are sure that you should be using `MediaStore`, probably you would need to query to see if the file already exists, rather than `insert()` a new file each time. – CommonsWare Aug 09 '22 at 12:53
  • Or easier you would remember the fileUri and use it again. – blackapps Aug 09 '22 at 12:57
  • 1
    Your method does create a new file everytime, if you want to overwrite the same file you should first look up the file (by file name or else), then overwrite it, you can check out my full answer here: https://stackoverflow.com/a/62879112/3466808 – Sam Chen Aug 09 '22 at 15:36
  • Thanks. I think that I need to query it because this file is supposed to be there even if I uninstall and reinstall the application – alexmro Aug 10 '22 at 08:58

1 Answers1

1

Thanks to Sam Chen's answer and with some adaptations, this is my Kotlin solution

fun exportToFile(fileName: String, content: String) {
    val contentValues = ContentValues().apply {
        put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
        put(MediaStore.MediaColumns.MIME_TYPE, "text/plain")
        put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
    }

    val extVolumeUri: Uri = MediaStore.Files.getContentUri("external")

    // query for the file
    val cursor: Cursor? = context.contentResolver.query(
        extVolumeUri,
        null,
        MediaStore.MediaColumns.DISPLAY_NAME + " = ? AND " + MediaStore.MediaColumns.MIME_TYPE + " = ?",
        arrayOf(fileName, "text/plain"),
        null
    )

    var fileUri: Uri? = null

    // if file found
    if (cursor != null && cursor.count > 0) {
        // get URI
        while (cursor.moveToNext()) {
            val nameIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME)
            if (nameIndex > -1) {
                val displayName = cursor.getString(nameIndex)
                if (displayName == fileName) {
                    val idIndex = cursor.getColumnIndex(MediaStore.MediaColumns._ID)
                    if (idIndex > -1) {
                        val id = cursor.getLong(idIndex)
                        fileUri = ContentUris.withAppendedId(extVolumeUri, id)
                    }
                }
            }
        }

        cursor.close()
    } else {
        // insert new file otherwise
        fileUri = context.contentResolver.insert(extVolumeUri, contentValues)
    }

    if (fileUri != null) {
        val os = context.contentResolver.openOutputStream(fileUri, "wt")

        if (os != null) {
            os.write(content.toByteArray())
            os.close()
        }
    }
}
alexmro
  • 563
  • 4
  • 16
  • Is this working for you ? I am trying to do the same but the cursor is always 0 & creates new file every single time. – nethra gowda Aug 31 '23 at 06:10