Difference between getExternalFilesDir and getExternalStorageDirectory() - java

I understand that ExternalFiles is to be used on API 8 and up and getExternalStorageDirectory is for 7 and down. However I am a little confused between the use. For example I wanted to check that a folder that exists and previously you would use something like:
File ChildFolder = new File(Environment.getExternalStorageDirectory() + "/ParentFolder/Child");
However every example I see says to use getExternalFilesDir (null), File.ext. Since I am above API 8 I want to use this method but how do I just check for a folder? I will check for a files existence at another point but for now just want to see if the folders exist??

getExternalFilesDir()
It returns the path to files folder inside Android/data/data/your_package/ on your SD card. It is used to store any required files for your app (e.g. images downloaded from web or cache files). Once the app is uninstalled, any data stored in this folder is gone too.
getExternalStorageDirectory()
It returns the root path to your SD card (e.g mnt/sdcard/). If you save data on this path and uninstall the app, that data won't be lost.

First of all, we need to understand what is difference between Internal Storage, External Storage (aka primary external storage), and Secondary External Storage?
Internal Storage: is storage that is not accessible by the user, except via installed apps (or by rooting their device). Example: data/data/app_packageName
Primary External Storage: In built shared storage which is "accessible by the user by plugging in a USB cable and mounting it as a drive on a host computer". Example: When we say Nexus 5 32 GB.
Secondary External Storage: Removable storage. Example: SD Card.
getExternalFilesDir (String type)
It returns the path to files folder inside Android/data/data/your_package/ on primary external storage. Which is inbuilt storage.
Environment.getExternalStorageDirectory()
It will return the path of the secondary external storage directory

! IMPORTANT UPDATE ! for whoever comes across this question.
As this is a somewhat old question just wanted to provide some additional information. Since KitKat even apps that have WRITE_EXTERNAL_STORAGE permission are only allowed to write to Android/data/data/your_package/ on external storage, a.k.a getExternalFilesDir()
If you will try to write to getExternalStorageDirectory() + "/somefolder/anotherfolder/" you will get a SecurityException on most devices

!! IMPORTANT !!
Environment.getExternalStorageDirectory() is deprecated and Context#getExternalFilesDir(String), MediaStore, or Intent#ACTION_OPEN_DOCUMENT, should be used instead.
This method was deprecated in API level 29.
To improve user privacy, direct access to shared/external storage devices is deprecated. When an app targets Build.VERSION_CODES.Q, the path returned from this method is no longer directly accessible to apps. Apps can continue to access content stored on shared/external storage by migrating to alternatives such as Context#getExternalFilesDir(String), MediaStore, or Intent#ACTION_OPEN_DOCUMENT.
https://developer.android.com/reference/android/os/Environment.html#getExternalStorageDirectory()
Also beginning from Android.M developers need to ask for permissions at run time.
See more details in documentation here and this question
Environment.getExternalStorageDirectory() deprecated in API level 29 java

Related

Android 11 Storage Access and Java File Library

I have an android application already available on playstore. It is a file transfer app between PC to Android using localhost. I'm using following java function within it:
To create directory/file/show list of files and many other file functions(append, byte read/write etc):
file.mkdir
directory.listFiles();
file.createNewFile()
I had also put
requestLegacyExternalStorage="true"
And it is working fine on android 10 after giving sufficient read/write external storage permission.
But the problem is that these will not work on android 11 as requestLegacyExternalStorage will not work. I have used MANAGE_EXTERNAL_STORAGE and the app works perfect but the problem is that playstore is not allowing it. (Don't know why they rejected the update)
I have also used getExternalFilesDir and it works perfect but don't like data to be in android folder and remove if app is deleted.
I have also tried to use download location and it works but the problem is getExternalStorageDirectory is deprecated:
File file = new File(Environment.getExternalStorageDirectory()+"/"+Environment.DIRECTORY_DOWNLOADS,"FileChat");
So what I wanted to ask how can I manage/use file library for android 11 to read/write/create/delete files and directory. It should not be in android folder as this will be deleted after app is deleted. Can I used public directory like downloads? If I can, what is the alternative to getExternalStorageDirectory()?
I don't need to read user data. Just want to have a directory in which app can store files. The read function is working as file is picked by user using intent.
Thanks in advance.
Top-level directory write access of shared storage is not available in Android 11, however you can use the existing File APIs to access the media and download collection folders like /Pictures, /Downloads, /DICM etc. It won't be possible to create your app's own folder as top level directory but it is possible to create a dedicated sub-directory in the default collection folders.
To keep your app running as expected on Android 10, requestLegacyExternalStorage flag will also be required since access to shared storage on Android 10 was restricted via MediaStore APIs only.
If transfer is only for your apps own files then put them in
File file = new File(Environment.getExternalStoragePublicDirectory(DIRECTORY_DOCUMENTS),"FileChat");
Or use Storage Access Framework to let the user choose and or create a directory on external storage inclusive removable micro sd card.

getFilesDir() vs getExternalFilesDir(), which one is more recommended?

As far as I've noticed, using getFilesDir() to store data (camera captures in my case) is somewhat temporary. I say somewhat because if I close and reopen the app, I'm able to access the directory and files list, but not the file itself.
Is my logic wrong or is that by design?
Out of the 2 methods, which is more recommended in :
general
my case (privacy is needed)
Simply,
getFilesDir() refers to internal storage that cannot be accessible outside your application. It's not explorable by the device as well.
getExternalFilesDir() refers to external storage, it's a type of App-specific storage. this can be explorable as you find its directory in
data/data/your package name
In general, you may use external storage as internal storage may be limited.
For privacy, if you need you to file security, use getFilesDir() as it's not accessible outside your application as I mentioned before.
The main difference between the two is:
getFilesDir() - This path will be hidden from the user. This is more secure approach.
getExternalFilesDir() - Accessible by the user.
Received a good documentation on this which provides clear understanding:
http://androidvogella.blogspot.com/2015/12/getfilesdir-vs-getexternalfilesdir-vs.html
Update for the latest Android (currently Android 13)
In the old days getFilesDir() used to mean internal storage, and getExternalFilesDir() used to mean anything plugged in (usually an SD card).
These days phones don't have SD card slots, so the device emulates external storage by grabbing a slice of internal storage for the purpose. So the historic differences - that internal was faster and smaller, and external slower and larger - are generally no longer true.
In both cases apps get scoped storage - i.e. a directory they can access without permissions, which isn't accessible by any other app (though see below). This has been the case since Android 10 (but only enforced in Android 11).
Files stored under getFilesDir() and getExternalFilesDir() will be deleted when the app is uninstalled, but will persist until then. (If you're finding a file disappears before then, you have a different problem. I would suggest posting your code in a separate question).
The only major remaining difference between internal and external is that apps can get request a permission to read/write the entirety of external storage, including files it doesn't own. So don't use external for files that need to remain private to the app.
More information in this article: https://medium.com/#tdcolvin/demystifying-internal-vs-external-storage-in-modern-android-c9c31cb8eeec

java.lang.IllegalStateException: Not one of standard directories [duplicate]

Android Api 29 has big changes regarding files and folders.
I have not found a way so far to create a folder in the internal storage that is public visible.
Every folder I create can be seen by my app only.
I write an app that creates data files that shall be picked up by other apps, for instance the Total Commander to copy them to a destination.
Everything worked fine until I activated Api 29. Some of my clients DO use pixel phones and they use Android 10.
How can I create a folder and files in Android 10 that are public?
This has been deprecated:
Environment.getExternalStorageDirectory();
Environment.getExternalStoragePublicDirectory(type);
and when I use
File root = context.getExternalFilesDir(null);
The created files can only be seen by my app.
How can I achieve the behavior that was valid before Android 10?
Thanks in advance.
when I use File root = context.getExternalFilesDir(null); The created files can only be seen by my app
They can be seen by any app that uses the Storage Access Framework (e.g., ACTION_OPEN_DOCUMENT), if the user chooses the document that you place in that directory.
I write an app that creates data files that shall be picked up by other apps
Other apps have no access to external or removable storage on Android 10, except in the limited directories like getExternalFilesDir() or via non-filesystem means (ACTION_OPEN_DOCUMENT, MediaStore).
How can I create a folder and files in Android 10 that are public?
Use getExternalFilesDir() and related methods on Context. Or, use ACTION_CREATE_DOCUMENT or ACTION_OPEN_DOCUMENT_TREE and use the Storage Access Framework. In either case, the resulting documents can be used by other apps that also use the Storage Access Framework.
Starting from Android 10, you should use SAF, and let user choose the directory using ACTION_OPEN_DOCUMENT_TREE.
If you need a simple example. You can find it here
Alternatively, you could use requestLegacyExternalStorage = true in manifest when your app is not newly released. But, this is something that should not be used for future release, as this is a short-term solution provided by Google.
Note: In future releases of Android, user will not be able to pick the whole external file directory and Downloads directory, so unfortunately, keep in mind that we are not going to have access to these as well! For more information you can click here

how to grant full Write/Read files access on specifics folder in android Q

I noticed that my program on Android Q can not create any folder or save and open a file.
I've read Google's documentation but I did not find the answer or at least I did not understand Because there is a very small sample code, and as I figured out, every time you create a file, you need to open a special window
Someone can tell me how can I get a full access for special folder in sdcard?
I do not want to open a different window every time and confirm it
Long term, you have no means of forcing the user to give you access to a test/ directory on external storage.
You have three main options.
You can use getExternalFilesDir(), getExternalCacheDir(), or getExternalMediaDir(). These are methods on Context, and they each return a File pointing to a directory on external storage for which you have full read-write filesystem access. From the user's standpoint, these will be under Android/data/.../, where ... is your application ID.
Or, you can use ACTION_OPEN_DOCUMENT_TREE and the Storage Access Framework. Using startActivityForResult() with an ACTION_OPEN_DOCUMENT_TREE Intent will give you a Uri that points to a document tree, which may be on external storage, removable storage, or in the cloud. You can call takePersistableUriPermission() on a ContentResolver to get long-term access to that tree, and you can use DocumentFile.fromTreeUri() to work with that tree. However, this is not filesystem access — it is a bit closer to working with a Web server.
Or, you can add android:requestLegacyExternalStorage="true" to your <application> element in the manifest. This will give you legacy filesystem behavior on Android Q devices. This is scheduled to be removed for Android R, so this is not a suitable long-term solution.
I blogged about the Android Q storage changes a lot this year; here is my last(?) post on it.

Is getExternalFilesDir() private?

I'm trying to store music files users can download with my application, but I don't want them to be publicly visible to 99% of users (I'm excluding rooted devices or special cases)
I'm not worried about the people that go above and beyond to get the audio out by using special tools or a rooted phone.
I am trying to understand the docs but it's not 100% clear to me that getExternalFilesDir() is good to use for that purpose.
Also, the library I'm currently using uses the following line:
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath()
Is this 100% interchangeable if I just replace it with...
Environment.getExternalFilesDir(Environment.DIRECTORY_MUSIC).getAbsolutePath()
(notice I changed both the directory function, as well as the DIRECTORY type (from PICTURES to MUSIC)
Thanks
Is getExternalFilesDir() private?
No. Any user and any app (with READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE) can access external storage.
Is this 100% interchangeable if I just replace it with..
That won't compile due to imbalanced parentheses. Also, the values are different (PICTURES versus MUSIC). Ignoring that, it is "interchangeable" insofar as they will both work and will both be on external storage. However, they are not the same thing. The first one is the user's standard PICTURES directory; the second one is a directory dedicated for pictures that is unique to your app. Also, the former requires WRITE_EXTERNAL_STORAGE on all devices; the latter requires it only for Android 4.3 and below.
I don't want them to be publicly visible to 99% of users (I'm excluding rooted devices or special cases)
Use internal storage (e.g., getFilesDir()).
Use getFilesDir() instead. Thats private app memory.
if you put "." before folder name this folder be hidden
e.g:
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root + "/.myFolderName");

Categories