Saving Files in Android - For Beginners (Internal / External Storage)
P

2

18

I'm very new to android development and I need a beginners help please...

I am creating an app that should have 2 directories, a Databases directory and an Images directory, just like Whatsapp has.

I want to see those directories in the File Manager when I'm browsing my phone, just like you see other apps folders. I tried everything I found here, to create it in the Internal storage and in the External storage from code. The folders seem to be created, but when I browsed my phone's File Manager, I couldn't find the folder with my app name and inside it my Databases and Images folders... What am I doing wrong? do I need to create those folders in the android studio as adding folders? or do I need to create it from code?

Can you please give me the actions I need to do to accomplish this task? I'm using android studio 3.1.3. Thanks for the helpers! :)

Ploy answered 27/7, 2018 at 21:43 Comment(0)
F
28

The terms "Internal Storage" and "External Storage" might be confusing at first, because Google's intentions are different from what we would expect & know from our day-to-day use of language: "External" doesn't necessarily mean the "SD Card". This guy made a great article about the terminology confusion

According to your intentions, you'd want to be working with the External Storage concept. The differences are well explained in the Documentation, but I'll shortly brief them to you here.

At the end I'll provide you an example, but first lets know the basics:

Internal Storage

  • Files are accessible by only your app
  • Files are removed when your app is uninstalled
  • Files are always available (meaning they files will never be saved on a removable memory)

External Storage

  • Files are fully readable by other apps (including any variant of File Manager app, in your case)
  • Files aren't necessarily removed when your app is uninstalled - explained later
  • Files availability isn't guaranteed (can be deleted by other apps / removable memory)

So now that we know you need External Storage, there are several things needed to be done before starting:

  • Require Permissions (read/write) inside your Manifest.xml file, depending on your needs:
    <manifest ...>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ...
    </manifest>

Each permission stands by its own, meaning you don't need to have both if, for example, you only wish to read files instead of writing them

  • Verify that storage is available - this is done on runtime, and is well explained inside the documentation. We need to make sure the storage is mounted into the device / its state is not problematic somehow in a way that would cause a failure of read/write requests.

Example Time!

In the given method, we will save a text file inside the root directory.

Credits to this article

public void writeFileExternalStorage() {

    //Text of the Document
    String textToWrite = "bla bla bla";

    //Checking the availability state of the External Storage.
    String state = Environment.getExternalStorageState();
    if (!Environment.MEDIA_MOUNTED.equals(state)) {

        //If it isn't mounted - we can't write into it.
        return;
    }

    //Create a new file that points to the root directory, with the given name:
    File file = new File(getExternalFilesDir(null), filenameExternal);

    //This point and below is responsible for the write operation
    FileOutputStream outputStream = null;
    try {
        file.createNewFile();
        //second argument of FileOutputStream constructor indicates whether
        //to append or create new file if one exists
        outputStream = new FileOutputStream(file, true);

        outputStream.write(textToWrite.getBytes());
        outputStream.flush();
        outputStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

I'd like to answer specifically to some of your questions:

do I need to create those folders in the android studio as adding folders? or do I need to create it from code?

Definitely not via the Android Studio. These are your projects folder, containing your code. The way to do it is mentioned above.

I couldn't find the folder with my app name and inside it my Databases and Images folders... What am I doing wrong?

Probably saved your files as Internal Storage ones / saved them as project folders as you mentioned earlier - and those wouldn't (and shouldn't) show up.


Useful things to know

There are 2 types of directories: public and private.

Private

  • Not accessible by the Media Store
  • Files are removed when app is uninstalled
  • Retrieved by getExternalFilesDir(...) method

Example: the WhatsApp directory (in my phone) is located right at the root level. Calling it would be: getExternalFilesDir("WhatsApp/...")

Public (Downloads/Movies/Images libraries)

  • Files are scanned by the MediaStore
  • Retrieved by Environment.getExternalStoragePublicDirectory(...) method

Example: getting the Documents folder would look like: Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)

Fraternize answered 28/7, 2018 at 2:17 Comment(8)
Thank you so much for the detailed and fast answer! just one more question about it. the path on my phone of the file I created is: /storage/emulated/0/Android/data/com.example.../files/FileName, when I used getExternalFilesDir. I wanted to create the directories on: /storage/emulated/0/AppName, so I used Environment.getExternalStorageDirectory(). On debug, the path was correct and the folder seemed to be created, but I can't find it on the phone and on the pc browse. where did I wrong here? for WhatsApp, for example, the path is /storage/emulated/0/WhatsApp/Ploy
The code I used to create the folder is: String DirName = "MyAppName"; File dir = new File(Environment.getExternalStorageDirectory(), DirName ); if (!dir.exists()) { dir.mkdirs(); }Ploy
I think you want to use new File(getExternalFilesDir(), DirName) instead of getExternalStoragePublicDirectory(). Another thing: File is supposed to point at a File, and not a Directory. try to change DirName to "MyAppName/TestFile.txt" and see if it works for youFraternize
With getExternalFilesDir(), the path is /storage/emulated/0/Android/data/com.example.../DirName/files/, and I want the path to be /storage/emulated/0/DirName/. is using new File(Environment.getExternalStorageDirectory(), DirName ) fot this is not correct? and for the changing DirName to "MyAppName/TestFile.txt", I want to create an empty dir and fill it with the app commands in code, is there other way to do that? and why I don't see the created dir? thanks again for all the help! :) (תודה רבה!)Ploy
And what is the correct way to create an empty dir by not using File?Ploy
I'm sorry - was confused about the getExternalFilesDir. I found out what your problem might be (I tried it myself now, it works) - its a permission issue: go to your phone settings -> apps -> find your app and set Storage permission to true. Also, before you publish your app - you'd want to make a popup dialog requesting the permission for users with android version > 6 (Marshmallow). the permission setting in the Manifest.xml isn't enough for Marshmallow and above. Try and let me know if it worked. בכיף :)Fraternize
Yes, it worked! that was the issue! Thanks, you helped me a lot! :) מאד מעריכה, תודה רבה! :)Ploy
outputStream.write(cashback.getBytes()) - I think you meant textToWrite, not cashback. ;)Sholom
G
3

The main answer really helped me out and I couldn't have gotten to this without that great answer.

But I had a few difficulties with getting the storage directory (because of changes to API over time) and I'm using Kotlin so I thought I'd just share my final code that I used.

Mine also returns a String message (absolute path to the file is success, and error message otherwise).

I've also added some Log statements so you can watch what is happening.

fun writeFileExternalStorage() :String {

        var fileData : String = "test this"
        
        Log.i("FirstFrag", "in writeFileExternalStorage")
        //Checking the availability state of the External Storage.
        val state = Environment.getExternalStorageState()
        if (Environment.MEDIA_MOUNTED != state) {

            Log.i("FirstFrag", "Couldn't get file system.")
            return "Couldn't write file."
        }

        var file =File(requireContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "test.txt")

        Log.i("FirstFrag", file.absolutePath)
        //This point and below is responsible for the write operation
        var outputStream: FileOutputStream? = null
        try {
            Log.i("FirstFrag", "creating new file")
            file.createNewFile()
            Log.i("FirstFrag", "file created")
            //second argument of FileOutputStream constructor indicates whether
            //to append or create new file if one exists
            outputStream = FileOutputStream(file, true)
            outputStream?.write(fileData.toByteArray())
            outputStream?.flush()
            outputStream?.close()
            Log.i("FirstFrag", "wrote file!")
            return file.absolutePath
        } catch (e: Exception) {
            Log.i("FirstFrag",e.message.toString())
            return e.message.toString() + "\nPlease check that you have a valid filename."
        }
        finally {
            isRetrievingFile = false;
        }
    }
Goins answered 3/6, 2021 at 16:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.