23

I'm still pretty much a beginner in kotlin and android studio. I can access most of the android widgets but I cannot access files and so far I managed to come across only the following code which does not work. The app crashes...

var recordsFile = File("/LET/Records.txt")
recordsFile.appendText("record goes here")

It will be much appreciated if I can also know how to create the file at a specific location. Like at root directory or internal storage or in a file in the internal storage. Thanks..

Khayyam
  • 703
  • 3
  • 7
  • 12

5 Answers5

44

You need to use internal or external storage directory for your file.

Internal:

val path = context.getFilesDir()

External:

val path = context.getExternalFilesDir(null)

If you want to use external storage you'll need to add a permission to the manifest:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Create your directory:

val letDirectory = File(path, "LET")
letDirectory.mkdirs()

Then create your file:

val file = File(letDirectory, "Records.txt")

Then you can write to it:

FileOutputStream(file).use {
    it.write("record goes here".getBytes())
}

or just

file.appendText("record goes here")

And read:

val inputAsString = FileInputStream(file).bufferedReader().use { it.readText() }
TpoM6oH
  • 8,385
  • 3
  • 40
  • 72
  • I think you have to use a call to .mkdirs() in there somewhere in the case where "/LET" may not yet exist. Also, for writing, he can just use file.appendText (which eventually resolves to something similar to what you've written, except that appendText sets the character set to UTF8) – Les Jul 20 '17 at 01:29
  • 1
    do you use `android.content.Context`? – TpoM6oH Jul 20 '17 at 09:52
  • 3
    If you are inside an activity you can just call `getFilesDir()`, otherwise you will need to get a context object. In a fragment you can call `getContext().getFilesDir()`. – TpoM6oH Jul 20 '17 at 10:05
  • I managed to get internal storage path using Environment. getExternalStorageDirectory().getPath() And assigned file using File(filePath//which is the internal storage path , "/LET/HelloWorld.txt") But I cannot write to it. App crashes. I tried writeText and appendText... I cannot find how to create the file. When I check the storage, no folder or file has been created, and the app crashes on both... – Khayyam Jul 20 '17 at 10:07
  • Try to do `File(filePath//which is the internal storage path , "HelloWorld.txt")`, as @Les pointed above you'll need to create the `LET `directory if it does not exist. – TpoM6oH Jul 20 '17 at 11:22
  • 2
    None of the documentation explains why you need context, or where that's supposed to come from. Are there certain places where we're supposed to access (or not access) internal storage? It seems like one ought to be able to write to that directory whenever – Theo Bendixson Mar 05 '18 at 16:10
  • I don't think it is correct that you can just use `file.appendText(..)` if the file did not already exist. I believe the call to the `File` constructor just creates an object in memory, not a file on external storage. – Ellen Spertus Nov 21 '19 at 21:07
  • For those who have problem use instead: FileOutputStream(file).use { it.write("record goes here".toByteArray()) – Thanasis Dec 15 '19 at 14:17
  • Will this survive app uninstall? I tried it and it didn't. – fullmoon Oct 24 '22 at 13:14
  • @TpoM6oH ```val path = context.getFilesDir()``` This line doesn't work for me. The variable context is an unresolved reference. Was I supposed to initialize it first somewhere? How? – James Read Oct 29 '22 at 21:57
26

Kotlin has made file reading/writing quite simple.

For reading/writing to internal storage:

context.openFileOutput(filename, Context.MODE_PRIVATE).use {
    it.write(message.toByteArray())
}
.
.
.
val file = File(context.filesDir, "myfile.txt")
val contents = file.readText() // Read file

For reading/writing to external storage:

val file = File(Environment.getExternalStorageDirectory()+"/path/to/myfile.txt")
file.writeText("This will be written to the file!")
.
.
.
val contents = file.readText() // Read file
Branson Camp
  • 641
  • 1
  • 9
  • 18
9

I just want to add on to TpoM6oH's answer. When working with Files, you may be not guaranteed with 100% success on the file operations you intend. So, it is a better practice to try and catch for exceptions like filenotfoundexception etc. and take a due care about the flow of program control.

To create a file at the external storage in Android, you can get the location using

Environment.getExternalStorageDirectory()

and check if the location exists. If it does not, create one and continue creating and writing your file using Kotlin

val sd_main = File(Environment.getExternalStorageDirectory()+"/yourlocation")
var success = true
if (!sd_main.exists())
    success = sd_main.mkdir()

if (success) {
    val sd = File("filename.txt")

    if (!sd.exists())
        success = sd.mkdir()

    if (success) {
        // directory exists or already created
        val dest = File(sd, file_name)
        try {
            // response is the data written to file
            PrintWriter(dest).use { out -> out.println(response) }
        } catch (e: Exception) {
            // handle the exception
        }
    }
} else {
    // directory creation is not successful
}

Hope this helps.

arjun
  • 1,645
  • 1
  • 19
  • 19
2

In 5 lines: create file to internal directory if not exists, write to file, read file

val file = File(ctx.filesDir, FILE_NAME)
file.createNewFile()
file.appendText("record goes here")
val readResult = FileInputStream(file).bufferedReader().use { it.readText() }
println("readResult=$readResult")
the_prole
  • 8,275
  • 16
  • 78
  • 163
0
fun loadWords(context: Context): ArrayList<String> {
        
    val Word = ArrayList<String>()
        var line: String
        var word = ""
        var weight = 0
        try {
            val reader: BufferedReader
            val file = context.assets.open("spam_keywords.txt")
            reader = BufferedReader(InputStreamReader(file))
            while ((reader.readLine()) != null) {
                line = reader.readLine()
                val st = StringTokenizer(line)
                while (st.hasMoreElements()) {
                    word = st.nextElement().toString()
                }
                Word.add(word)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        println(Word)
        return Word 
    }
David Buck
  • 3,752
  • 35
  • 31
  • 35