I am using Nougut 7.1.1 device
When I run the below given code, file is stored in device or internal storage "emulated/0..." but I want to store it in removable memory card.
I logged getExternalStorageState() and it shows mounted.
I tried using Environment.getExternalStorageDirectory() also,stored in "emulated/0...", no result
I have used permissions in manifest file too as below:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Note: However, both internal and external(memory card) storage consist of "Hello World" folder like:
Android/Data/com.example.myapplication/files/Hello World/
but stored file(myData2.txt) is present only in "Hello World" folder of internal storage
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("tag", Environment.getExternalStorageState().toString());
Log.i("tag", getExternalFilesDir(null).toString());
savePrivate();
}
public void savePrivate() {
String info = "Written";
File folder = getExternalFilesDir("Hello World");// Folder Name
File myFile = new File(folder, "myData2.txt");// Filename
writeData(myFile, info);
}
private void writeData(File myFile, String data) {
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(myFile);
fileOutputStream.write(data.getBytes());
Toast.makeText(this, "Done" + myFile.getAbsolutePath(), Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Changed my savePrivate() method as below and it worked like a charm!!
As per #CommonsWare suggested,using getExternalFilesDirs() returned available array of locations from which I could select particular storage,In my case folder[0] pointed to "emulated/0.." and folder[1] pointed to removable storage (storage/15C8-119Z/...).
public void savePrivate() {
String info = "Written";
File[] folder = getExternalFilesDirs("backup");// Folder Name
Log.i("tag", String.valueOf(folder[1]).toString());
File myFile = new File(folder[1], "myData2.txt");// Filename
writeData(myFile, info);
}
but stored file(myData2.txt) is present only in "Hello World" folder of internal storage
It is stored in what the Android SDK refers to as external storage. External storage is not removable storage, nor is it what the Android SDK refers to as internal storage.
When I run the below given code, file is stored in device or internal storage "emulated/0..." but I want to store it in removable memory card.
First, you are passing an invalid value to getExternalFilesDir(). Please follow the documentation and pass in a valid value (e.g., Environment.DIRECTORY_MUSIC) or null.
To write to removable storage, replace getExternalFilesDir() with getExternalFilesDirs() and choose a location from the returned array of locations. If that array has 2+ entries, 1+ of them will be on removable storage.
Beginning with Android 4.4 (API level 19), reading or writing files in your app's private external storage directory—accessed using getExternalFilesDir()—does not require the READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE permissions. So if your app supports Android 4.3 (API level 18) and lower, and you want to access only the private external storage directory, you should declare that the permission be requested only on the lower versions of Android by adding the maxSdkVersion attribute:
<manifest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
</manifest>
Select between multiple storage locations
Sometimes, a device that allocates a partition of the internal memory for use as the external storage also provides an SD card slot. This means that the device has two different external storage directories, so you need to select which one to use when writing "private" files to the external storage.
Beginning with Android 4.4 (API level 19), you can access both locations by calling getExternalFilesDirs(), which returns a File array with entries for each storage location. The first entry in the array is considered the primary external storage, and you should use that location unless it's full or unavailable.
If your app supports Android 4.3 and lower, you should use the support library's static method, ContextCompat.getExternalFilesDirs(). This always returns a File array, but if the device is running Android 4.3 and lower, then it contains just one entry for the primary external storage (if there's a second storage location, you cannot access it on Android 4.3 and lower).
Check official documentation for detailed description.
Hope this helps.
This is a function in context where you could get all mounted storage's
ContextCompat.getExternalFilesDirs(context,Environment.YOUR_DIRECTORY);
So , First is your primary internal storage and second will be your mounted sd-card if mounted . You may use this function that returns the sd-card directory if sd-card mounted else the internal-storage directory
File getDir(Context context){
File[] mountedStorage = ContextCompat.getExternalFilesDirs(context,Environment.DIRECTORY_PICTURES);
return mountedStorage[mountedStorage.length-1];
}
With Kotlin
val dir:File = ContextCompat.getExternalFilesDirs(context,Environment.YOUR_DIRECTORY).last()
Related
I have an app that needs access to an android phone's internal storage, such as the Download folder. However when I try to list the files it alimport
java.io.File;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class Main extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
File root = new File("/"); // Works
File mnt = new File("/mnt/"); // Works
File mnt2 = new File("/mnt/m_internal_storage"); // Crashes
File cus = new File("/custom/"); // Works
File f = new File("/sdcard/"); // Crashes
String[] s = f.list();
for (int x = 0; x < s.length; x++) {
Log.println(Log.ASSERT, "#", s[x]);
}
}
}
This code will print every file in the directory. It works with root, mnt & cus but crashes when it tries to get the list of f & mnt2, returning a null array to s. How do I access the internal file storage?
I have also tried using Environment's functions with most failing and I even have Read/Write permissions for External Storage enabled.
Compiling for 7.0.
Targeting API 23.
Min sdk API 18.
I have an app that needs access to an android phone's internal storage, such as the Download folder.
The Download folder that users see is on what the Android SDK calls external storage.
How do I access the internal file storage?
Use Environment.getExternalStorageDirectory(). Never hardcode paths. For example, vanishingly few devices on the face of the planet have /mnt/m_internal_storage, /custom/, or /sdacard/.
I have also tried using Environment's functions with most failing and I even have Read/Write permissions for External Storage enabled.
Perhaps you did not implement runtime permissions.
In your code it is "File f = new File("/sdacard/"); // Crashes", which should be "/sdcard/".
if you want internal file of your app, means in app.package
/sdcard/data/data/pack_name/files/fileName
you need to access it like this
File p = getApplicationContext().getFileStreamPath("FileName");
Edit
other than this you have to ask for runtime permissions
and Download Path is not Internal Storage! it defines as external.
everything that normal users can access (without root) in file manager is external storage. internal storage is not like internal sdcard and then micro sdcard. Internal Storage is what belong to ur package
read it:
https://developer.android.com/guide/topics/permissions/requesting.html
I am unable to write file to external SD Card . I get error message EAcess denied. I have searched a lot on internet and found that from Android 4.4 + android's Storage Access Framwork (SAF) is required to write file.
But I am using some android applications which are able to write(Create/Delete/Rename) file on SD Cards. They are not using SAF.
So please help me as to how can I do this without using SAF framwork.
Thanks
There are a lot of confusions talking about External Memory of Android. It doesn't point to Removable SD MICRO CARD actually. So, what Google thinks "external memory" means
Refer to Android API Document
Every Android-compatible device supports a shared "external storage"
that you can use to save files. This can be a removable storage media
(such as an SD card) or an internal (non-removable) storage. Files
saved to the external storage are world-readable and can be modified
by the user when they enable USB mass storage to transfer files on a
computer.
The fact is Environment.getExternalStorageDirectory() and Context.getExternalFilesDirs() could return an emulated External Memory located inside the Internal storage. Thus, these functions themselves don't give an expected results. The SECONDARY_STORAGE environment variable can help to get a real path of removable memory but writing on root of this isn't allowed because of OEM implementation. In this case, we should try to get app's data folder by Context.getExternalFilesDirs() or ContextCompat.getExternalFilesDirs() on which app's data file is allowed to be read and written.
I solve my problem by using below method, please check it and hope it helps you overcome your issues.
#TargetApi(Build.VERSION_CODES.KITKAT)
private String getRemovablePath(){
String secondaryStore = System.getenv("SECONDARY_STORAGE");
if (secondaryStore != null){
secondaryStore = secondaryStore.split(":")[0];
secondaryStore += File.separator + "Backups/";
File file = new File(secondaryStore);
if((file.mkdir() || file.isDirectory()) && isFileWritable(secondaryStore)){
return secondaryStore;
} else {
secondaryStore = null;
}
}
// try again by fix address
if(secondaryStore == null){
if (new File("/Removable/MicroSD/").exists()){
secondaryStore = "/Removable/MicroSD/";
} else if( new File("/storage/extSdCard/").exists()){
secondaryStore = "/storage/extSdCard/";
} else if( new File("/storage/sdcard1/").exists()){
secondaryStore = "/storage/sdcard1/";
} else if( new File("/storage/usbcard1/").exists()){
secondaryStore = "/storage/usbcard1/";
} else if( new File("/storage/external_SD/").exists()){
secondaryStore = "/storage/external_SD/";
}
/** add more fix addresses you know */
secondaryStore += "Backups/";
File file = new File(secondaryStore);
if((file.mkdir() || file.isDirectory()) && isFileWritable(secondaryStore)){
return secondaryStore;
} else {
secondaryStore = null;
}
}
/** Try data folder*/
if(secondaryStore == null){
int ver = Build.VERSION.SDK_INT;
File[] externalRoots = null;
if(ver <= Build.VERSION_CODES.JELLY_BEAN_MR2){
externalRoots = ContextCompat.getExternalFilesDirs(getBaseContext(), null);
} else {
externalRoots = getExternalFilesDirs(null);
}
if(externalRoots.length > 1){
secondaryStore = externalRoots[1].getAbsolutePath() + File.separator;
return secondaryStore;
} else {
secondaryStore = null;
}
}
return secondaryStore;
}
please check the link, where present issue:
issue
for access to external memory in previous android versions there is no problem. current possess improvements
Android API < 23
Your Android Manifest must declare the specific user permission:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
You also have to declare the reading permission if you also intend to read files:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
User permissions must be placed before the application section, like this:
<manifest>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
...
<application>
Source of my explanation and examples on how to save files can be found in the official documentation.
Android 6 (API 23)
Things get a bit different starting with Android API 23 because user permissions have to be asked to the user in runtime when needed. A valid answer to this was already given here.
SAF is only needed if you have to write to any location on the SD Card. To write to your app-specific directory on the SD Card, you can use context.getExternalFilesDirs. One of the paths returned will be the path of the your app specific folder on the SD Card.
Again, this is manufacturer dependent as well. If the manufacturer has not set the SECONDARY_STORAGE environment variable, the paths returned by getExternalFilesDirs will not contain the SD Card path.
I'm using Android Studio. I have my project set to require API version 11. The Emulator is set for Nexus 5 API23 (standard default settings).
I want to have my application write a simple text file to a location where I can pull the text files created onto my computer by plugging in with a USB cable. So it needs to be in the public external storage.
For whatever reason I can't get the code to create a folder for my text files to go into. I have paired my code down to this little nugget in a "Utilities" class I have:
public static boolean createTheDangFolder(Context c, String fileName, String body) {
boolean saved = true;
//File dir = new File(c.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "MyCustomFolder");
File dir = new File(Environment.getExternalStorageDirectory(), "MyCustomFolder");
if (!dir.exists()) {
saved = dir.mkdirs();
}
return saved;
}
This function always returns false. If I trade comments on the "File" line it will return true but the commented out line is the app memory and I can't access the files via USB.
I have this line in my Manifest file:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I can't for the life of me figure out why it's not working and none of the other questions on the site have given me a solution that works.
They changed the permissions to external storage in KitKat. You can only write to public folders (like downloads) and to your own app's private directory on external storage.
I want to save a text file to the SD card I inserted into my HTC One M8 running lollipop. However when I run this code it saves to internal storage instead.
String FILENAME = "mysavefile.txt";
File file = new File(Environment.getExternalStorageDirectory(), FILENAME);
if (isExternalStorageWritable()) {
errorSD.setVisibility(View.INVISIBLE);
try {
FileOutputStream fos = new FileOutputStream(file, false);
fos.write(allInformation.getBytes(), 0, 81);
fos.close();
successfulSubmissionToast();
} catch (FileNotFoundException e) {
e.printStackTrace();
errorSD.setVisibility(View.VISIBLE);
} catch (IOException e) {
e.printStackTrace();
}
It should be saving to
/storage/ext_sd
but instead it is saving to
/storage/emulated/0
Then I tried manually entering in the location of my SD card to see if that would work but it ended up throwing the FileNotFoundException
File file = new File("/storage/ext_sd", FILENAME);
Edit:
I believe the issue is that there are multiple external storages. One being permanent and one temporary. The question is how do you access the second one.
First of all, we need to understand about 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.
getExternalStorageDirectory ()
It will return path of the primary external storage directory
To access removable SD (Secondary external storage) there are below APIs:
getExternalFilesDirs(), getExternalCacheDirs(), and getExternalMediaDirs()
Check there documentation for further information
If the Android device following the guide here when deal with multiple external storage, we can use the following code to detect where to write the data for Android kitkat or higher version.
final String APP_EXTERNAL_CACHE = "Android" + File.separator + "data"
+ File.separator + getPackageName() + File.separator + "cache";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
for (File file : getExternalCacheDirs()) {
if (file != null) {
String mountPoint = file.getAbsolutePath().replace(APP_EXTERNAL_CACHE, "");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (Environment.isExternalStorageRemovable(file)) {
Log.d(TAG, "removable external " + file.getAbsolutePath());
}
if (Environment.isExternalStorageEmulated(file)) {
Log.d(TAG, "emulated internal " + file.getAbsolutePath());
}
} else {
if (mountPoint.contains("emulated")) {
Log.d(TAG, "emulated internal " + mountPoint);
} else {
Log.d(TAG, "removable external " + mountPoint);
}
}
}
}
}
And declare the relating permission in the manifest.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
I want to save a text file to the SD card I inserted into my HTC One M8 running lollipop
You are welcome to try getExternalFilesDirs(), getExternalCacheDirs(), and getExternalMediaDirs() on Context. Note the plural form of the method name. For these methods, if they return more than one entry, the second and subsequent ones should be on removable media, pointing to directories that you can read and write, without any particular permission (e.g., WRITE_EXTERNAL_STORAGE).
Outside of those locations, for devices that shipped with Android 4.4+, you have no access to removable storage.
I think it's because HTC one modified the sdcard mount point, you should try adb shell ls -l commands to find out which path the sdcard mounted.
For example in nexus 4:
lrwxrwxrwx root root 2015-03-24 18:26 sdcard -> /storage/emulated/legacy
drwxr-x--x root sdcard_r 2015-03-24 18:26 storage
and you should make sure it is not a link: ls -l /storage/emulated/legacy
lrwxrwxrwx root root 2015-03-24 18:26 legacy -> /mnt/shell/emulated/0
The path /mnt/shell/emulated/0 is actually sdcard path.
Try read How can I get external SD card path for Android 4.0+? too, this may help you a lot.
UPDATE
I tried this code:
String test = "/storage/emulated/legacy"; // work
//String test = "/mnt/shell/emulated/legacy"; // not work
File sdDir = new File(test);
if (sdDir.exists()) {
File file = new File(test, "test.sdcard");
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
So you'd better try /storage/emulated/* directories to find out which is exactly your sdcard.
i have given required permission :
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
hard-coded the path as "/sdcard/filename".
I guess Nexus don't have external SD support but S2 has, that I think might cause a problem in getting the path. How should I handle such a case gracefully?
On each Android Device you can get the path to the external storage like this
Environment.getExternalStorageDirectory()
I've a Nexus device and it works - also on my old milestone
Here is an example usage to create your own apps directory:
You should always check to see if the SDcard is available first because it could be mounted/teathered to a computer or be removed from the device.
private void SetDirectory() {
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
extStorageDirectory = Environment.getExternalStorageDirectory().toString();
File dbDirectory = new File(extStorageDirectory + "/yourAppName/whatever/");
myDirectory.mkdirs();// Have the object build the directory
} else if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED_READ_ONLY)) {
//TODO Make some kind of allert or Toast to warn/notify the user that the SDcard is needed.
}
}
You can use the android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED) method to check if the card is available anywhere within your application.