Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I have been getting a java.io.IOException: Not a directory exception for the following code:

fun saveImage(IdNumber: Int, photoFile: File, plantType: Int) {
    val newImage = PlantPhoto(IdNumber, "ZZ Plant", photoFile, plantType)
    val dir = File(
        context.getExternalFilesDir("planio/dataclasses/${plantType}").toString()
    if (!dir.exists()) {
        dir.mkdirs()
    val dataClassLocation = File(dir, "$IdNumber")
    if (dataClassLocation.exists()) {
        dataClassLocation.delete()
        dataClassLocation.createNewFile()
    } else{
        //exception occurs here 
        dataClassLocation.createNewFile()
    val plantFile = FileOutputStream(dataClassLocation, true)
    val outStream = ObjectOutputStream(plantFile)
    outStream.writeObject(newImage)
    outStream.close()
    plantFile.close()
    Log.i(SaveTag, "Image saved successfully")

I have already checked that parent directories exist and since I am using an emulator that runs on API 29, getExternalFilesDir should not require permission to read and write to. But I am unsure as to why I am getting this exception since I should be able to create a new File inside another File as per this link.

Here is the stack trace:

 Caused by: java.io.IOException: Not a directory
    at java.io.UnixFileSystem.createFileExclusively0(Native Method)
    at java.io.UnixFileSystem.createFileExclusively(UnixFileSystem.java:317)
    at java.io.File.createNewFile(File.java:1008)
    at com.example.camera.presentation.CameraViewModel.saveImage(CameraViewModel.kt:68)
    at com.example.camera.presentation.CameraFragment$takePhoto$1.onImageSaved(CameraFragment.kt:167)
    at androidx.camera.core.ImageCapture$3.onImageSaved(ImageCapture.java:661)
    at androidx.camera.core.ImageSaver.lambda$postSuccess$0$ImageSaver(ImageSaver.java:253)
    at androidx.camera.core.-$$Lambda$ImageSaver$-JRZLUaKK7DQ1iBdZ_1qTGbYQrk.run(Unknown Source:4)
    at android.os.Handler.handleCallback(Handler.java:883)
    at android.os.Handler.dispatchMessage(Handler.java:100)
    at android.os.Looper.loop(Looper.java:214)
    at android.app.ActivityThread.main(ActivityThread.java:7356)
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 

Using @ALUFTW 's answer, I have modified my code to this:

    fun saveImage(IdNumber: Int, photoFile: File, plantType: Int) {
    val newImage = PlantPhoto(IdNumber, "ZZ Plant", photoFile, plantType)
    val dataClassLocation = File(context.getExternalFilesDir("planio/dataclasses/${plantType}/$IdNumber").toString())
    if (!dataClassLocation.exists()) {
        try {
            dataClassLocation.parentFile.mkdirs()
            dataClassLocation.createNewFile()
        } catch (e: IOException) {
            e.printStackTrace()
    val plantFile = FileOutputStream(dataClassLocation, true)
    val outStream = ObjectOutputStream(plantFile)
    // Method for serialization of object
    outStream.writeObject(newImage)
    outStream.close()
    plantFile.close()
    Log.i(SaveTag, "Image saved successfully")

And now I am getting a new java.io.FileNotFoundException: planio/dataclasses/1/filename: open failed: ENOENT (No such file or directory)

Thank you for your response, mkdirs returns false but I am confident that is because I have already made that directory during previous runtime attempts, and mkdirs only returns true if the directory was created and not if it exists or not. I also added 'Log.i(SaveTag, "${dir.absolutePath}")' and this also prints out the exact directory(file) I would like to save my files to. And I have also used Log.i(SaveTag, "${dir.exists()}") and this returned true. – Lisa Mar 2, 2021 at 23:30 returns false but I am confident that is because I have already made that directory during previous runtime attempts, a... No. As you only call mkdir if the directory does not exist yet. Which is good. But not checking return value and not handle accordingly is not good. You are complaining about not being able to create a file. But before that the directory is not created. – blackapps Mar 3, 2021 at 9:34 java.io.FileNotFoundException: planio/dataclasses/1/filename: open failed Of course. That is an impossible path. – blackapps Mar 3, 2021 at 9:38 "planio/dataclasses/${plantType}/$IdNumber" I think that it is not allowed to put a whole subdirectories train as parameter in getExternalFilesDir. Use only one subdirectory there. – blackapps Mar 3, 2021 at 9:40

The line dir.mkdirs() isn't creating a directory for you.

If it won't work- It will not throw exception but it will return false.

Try the following code:

File dataClassLocation_folder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/planio/dataclasses/${plantType}/");
dataClassLocation_folder.mkdirs();
File dataClassLocation_file = new File(dataClassLocation_folder,filename);
dataClassLocation_file.createNewFile();
                Thank you for your response. I'm not certain if java path strings require \/ or // since I couldn't find anything on this topic.
– Lisa
                Mar 2, 2021 at 23:44
                I have copy and pasted the code and it is giving me the following error through the catch  stack trace: java.io.IOException: No such file or directory. I think the directory exists but somehow createNewFile() isn't able to create a new File
– Lisa
                Mar 3, 2021 at 0:22
                Thank you, except now I am getting a new exception: java.io.FileNotFoundException: planio/dataclasses/1/filename: open failed: ENOENT (No such file or directory)
– Lisa
                Mar 3, 2021 at 1:01

I have now separated my subdirectories and my code is working :)

Turns out it is not allowed to put a whole subdirectories train as parameter in getExternalFilesDir.

fun saveImage(IdNumber: Int, photoFile: File, plantType: Int) {
    val newImage = PlantPhoto(IdNumber, "ZZ Plant", photoFile, plantType)
    val dir = File(
        context.getExternalFilesDir(null), "planio/dataclasses"
    if (!dir.exists()) {
        dir.mkdirs()
    val dirOne = File(dir, "$plantType")
    if(!dirOne.exists()){
        dir.mkdirs()
    val dataClassLocation = File(dirOne, "$IdNumber")
    if (dataClassLocation.exists()) {
        dataClassLocation.delete()
        dataClassLocation.createNewFile()
    } else{
        dataClassLocation.createNewFile()
    val plantFile = FileOutputStream(dataClassLocation, true)
    val outStream = ObjectOutputStream(plantFile)
    outStream.writeObject(newImage)
    outStream.close()
    plantFile.close()
    Log.i(SaveTag, "Image saved successfully")

Replace:

    val dir = File(
        context.getExternalFilesDir("planio/dataclasses/${plantType}").toString()

with:

    val dir = File(
        context.getExternalFilesDir(null), "planio/dataclasses/${plantType}"

...and see if you have better luck. The parameter to getExternalFilesDir() is a Directory type (downloads, pictures, audio, etc) returning the root of the path from the environment, not a subdirectory path, this one you must create inside the root.

Thank you for your response, but I am still getting the exact same exception and stack trace as the first time java.io.IOException: Not a directory – Lisa Mar 3, 2021 at 0:44

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.