11

I am writing a small app that reads files that must be regularly written to storage on the device from a source external to the device, be it USB, Bluetooth, Airdroid, etc. From what I've read, nothing like that can write to internal storage. I would like to manage the files in internal storage for access privacy.

My first solution is an activity that lets the user write files to external storage, and then tap a button to transfer them to internal storage. If this doesn't happen in n minutes, the files on external storage are destroyed. But, I a have since found out that getExternalStorageDirectory is pretty useless, because devices emulate external storage on internal storage, and Android can't know if and how this is done.

Yet I was wondering if there wasn't some sort of built-in activity that lets users upload or download files directly from internal storage, but without free access to the whole file structure of internal storage, like they have with internal storage.

As a last resort, maybe my app can receive the files over a TCP connection and write them to internal storage itself. It's messy, but so is trying to find an SD card. See the question Find an external SD card location.

NEW: The aim of this exercise is to find all .csv files in a directory on the SD card, let the user choose one, process it, and write an output file to the SD card. The user will enter a "Weight" value that will be used in the calculations for processing the file.

But, since Android is so unreliable at providing the location of really external storage, i.e. the SD card, I want to try and store the files in internal storage, where Android seems to be more honest and reliable about the location of that storage.

ProfK
  • 49,207
  • 121
  • 399
  • 775
  • You can store the files directly in the internal storage. https://developer.android.com/training/basics/data-storage/files.html – Prerak Sola Sep 01 '16 at 13:08
  • @PrerakSola But how? I've already read the doc you link to, before asking this question, and it says clearly,about internal storage, "Files saved here are accessible by only your app". So nearly the whole point of this question is how the user, which is not my app, and does not have access to internal storage, can get a file into internal storage. – ProfK Sep 01 '16 at 14:40
  • 1
    is your question, "how to write to internal storage accessible to user _and not to `data/data/package_name/` doing which would NOT allow other apps to access it_? – Saravanabalagi Ramachandran Sep 04 '16 at 09:30
  • `upload to` internal storage is _fuzzy_. Did you mean, `upload from` internal storage to perhaps web _or_ `write to` internal storage from web or external sources? – Saravanabalagi Ramachandran Sep 04 '16 at 09:34
  • @ZekeDran, "Upload **TO**" isn't that fuzzy for me. I think it clearly indicates, to some someone whose first language is English at least, that the "internal storage" is the destination, i.e. I want to put files in there, not read them or take them out from there. – ProfK Sep 05 '16 at 03:57
  • @ZekeDran Is there any internal storage accessible to the user, except that which most devices pretend is external? My main goal, is the because `getExternalStorageDirectory` is unreliable, I either have to manually find its path and let the app store it in a settings file, or find a way to let the app receive the file, and itself write it to storage not accessible to users. – ProfK Sep 05 '16 at 04:00
  • @ProfK While 'upload **TO**' internal storage solidly says that the destination is _internal storage_, it's **UPLOAD** that casts doubt! If your app's creating it, it would not be more befitting, if not wrong, to call it **UPLOAD** than calling it **WRITE**. And if it's not created by your app, then it would be a **COPY** or a **MOVE** op, when it writes to the internal storage; – Saravanabalagi Ramachandran Sep 05 '16 at 08:52

2 Answers2

4

TLDR: getExternalStorageDirectory() and getExternalFilesDirs()[0] (API 19+) should return "primary" storage location, i.e, internal storage.

EDIT: if you just want to write to eMMC and don't care about it being private, just use getFilesDir() and its guaranteed you're writing to eMMC.


Explanation:

To avoid obscurities and for convenience, I will use the following terms

  1. PrivateStorage: App's Private Storage in internal memory - /data/data/package name
  2. eMMC: Phone's internal storage
  3. SD: Phone's expandable storage (removable)

If I understood your question right, you don't want to write to PrivateStorage which would NOT allow other apps to access that data. So the objective is to write to eMMC and to be more specific, publicly accessible eMMC and not in eMMCs app's private space.

According to Android Docs (API 1),

Environment.getExternalStorageDirectory() returns the primary external storage directory. This directory may not currently be accessible if it has been mounted by the user on their computer, has been removed from the device, or some other problem has happened. You can determine its current state with getExternalStorageState().

And according to API 19 docs,

You can now read and write app-specific files on secondary external storage media, such as when a device provides both emulated storage and an SD card. The new method getExternalFilesDirs() works the same as the existing getExternalFilesDir() method except it returns an array of File objects.The first entry in the returned File array is considered the device's "primary" external storage, which is the same as the File returned by existing methods such as getExternalFilesDir().

Summing up, both getExternalStorageDirectory() and getExternalFilesDirs()[0] should return "primary" storage location, which is eMMC. however in practice you can notice that what it returned might not necessarily be eMMC, for a few phones (KarbonnTitiniumS2, XoloX3000 and many other phones)

Here are some snapshots to second that sentence: This phone TitaniumS2 was running 4.2 so I couldn't use getExternalFilesDirs()

enter image description here enter image description here

You can also notice that, for the same reason, ES Explorer has wrongly identified /sdcard0 as internal storage (eMMC) and /sdcard1 as external storage (SD) in both old and new versions and indeed continue to tell users that sdcard0 as internal storage.

Also, an issue for finding non-primary (SD) storage, was raised.

It seems there is no API function for finding non-primary external storage devices and google has no intention of fixing the situation, leaving applications to use hacky workarounds like parsing all currently mounted filesystems. It's pretty terrible for a current-gen OS to not properly support something as basic as accessing files on an inserted USB stick.

CL.
  • 173,858
  • 17
  • 217
  • 259
Saravanabalagi Ramachandran
  • 8,551
  • 11
  • 53
  • 102
  • @ProfK, if you can tell what **exactly** you want to do in your app, people can suggest workarounds and possible hacks; you have mentioned it, but not with enough details (like what you want to ultimately achieve) to find a hack i presume :) – Saravanabalagi Ramachandran Sep 05 '16 at 12:01
  • My aim in writing to is not to prevent other apps accessing the data, but because Android knows where that data is, where finding the real external storage is quite a mission. – ProfK Sep 06 '16 at 04:25
  • what is this app for? what does it do? why do you want to access eMMC specifically? Is that _just_ for performance reasons? – Saravanabalagi Ramachandran Sep 06 '16 at 17:28
0

Hope this help ...

you are able to get the file that user wants to upload, and can read the data ... then you want to write them to your Applications path ...

Correct me if I'm wrong...

here is how you can try to write file to your application's path... mine one is /data/data/com.test.internalstorage/files

try {
    File filesDir = getApplicationContext().getFilesDir();
    Log.d(TAG, "  Files -> 1 context.getFilesDir()-=> " + filesDir);
    Log.d(TAG, "  Files -> 1 context.getFilesDir().getName-=> " + filesDir.get-name());
    Log.d(TAG, "  Files -> 1 context.getFilesDir().getAbsolutePath-=> " + filesDir.getAbsolutePath());
    Log.d(TAG, "  Files -> 1 context.getFilesDir().getCanonicalPath-=> " + filesDir.getCanonicalPath());
    Log.d(TAG, "  Files -> 1 context.getFilesDir().getPath-=> " + filesDir.getPath());
    String[] lst = getApplicationContext().getFilesDir().list();
    for (int i=0; i< lst.length; i++){
        Log.d(TAG, "  Files -> 1 context.getFilesDir()list("+i+")-=> " + lst[i]);
    }
    String FILENAME = "hello_file5";
    String string = "hello world!";

    FileOutputStream fos = null;

    fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
    fos.write(string.getBytes());
    fos.close();


    Log.d(TAG, "  Files ");"
    File nw_filesDir = getApplicationContext().getFilesDir();
    Log.d(TAG, "  Files -> 2 context.getFilesDir()-=> " + nw_filesDir);
    String[] nw_lst = getApplicationContext().getFilesDir().list();
    for (int i=0; i< nw_lst.length; i++){
        Log.d(TAG, "  Files -> 2 context.getFilesDir()list("+i+")-=>  " + nw_lst[i] +
                " -> " + new File(nw_filesDir,nw_lst[i]).getParentFile());
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

output is

D/_TAG_:   Files -> 1 context.getFilesDir()-=> /data/data/com.test.internalstorage/files
D/_TAG_:   Files -> 1 context.getFilesDir().getName-=> files
D/_TAG_:   Files -> 1 context.getFilesDir().getAbsolutePath-=> /data/data/com.test.internalstorage/files
D/_TAG_:   Files -> 1 context.getFilesDir().getCanonicalPath-=> /data/data/com.test.internalstorage/files
D/_TAG_:   Files -> 1 context.getFilesDir().getPath-=> /data/data/com.test.internalstorage/files
D/_TAG_:   Files -> 1 context.getFilesDir()list(0)-=> hello_file
D/_TAG_:   Files -> 1 context.getFilesDir()list(1)-=> hello_file2
D/_TAG_:   Files -> 1 context.getFilesDir()list(2)-=> hello_file3
D/_TAG_:   Files -> 1 context.getFilesDir()list(3)-=> hello_file4
D/_TAG_:   Files 
D/_TAG_:   Files -> 2 context.getFilesDir()-=> /data/data/com.test.internalstorage/files
D/_TAG_:   Files -> 2 context.getFilesDir()list(0)-=>  hello_file -> /data/data/com.test.internalstorage/files
D/_TAG_:   Files -> 2 context.getFilesDir()list(1)-=>  hello_file2 -> /data/data/com.test.internalstorage/files
D/_TAG_:   Files -> 2 context.getFilesDir()list(2)-=>  hello_file3 -> /data/data/com.test.internalstorage/files
D/_TAG_:   Files -> 2 context.getFilesDir()list(3)-=>  hello_file4 -> /data/data/com.test.internalstorage/files
D/_TAG_:   Files -> 2 context.getFilesDir()list(4)-=>  hello_file5 -> /data/data/com.test.internalstorage/files

Corrections and Suggestions are welcomed !!!

Bhuro
  • 348
  • 4
  • 22
  • Thanks, but not like that. I want to get the files from where the user saves them on the device's SD car, via USB say, and process them, but I can't reliably find the path they are at, so I want to let the user save them directly to internal storage. The USB connection will have no access to that, so I'm asking for a way that the device/app can save the files from outside the device to the internal storage. – ProfK Sep 07 '16 at 02:40
  • In that case, I guess the Permission on the files will not allow you (I mean the USB Interface) as it will be belonging to `Others group` as per `Linux File Permissions` ... Where as Applications are running as Part of System, Pragmatically you can have access!! – Bhuro Sep 07 '16 at 03:26
  • One thing may help us if somehow, pragmatically,we can create a directory with 755 or 777 permission in the Internal Storage under your Application folder , here in my case `/data/data/com.test.internalstorage/files`, and then `adb` or `abd shell` commands will help you to transfer the files to this location,.... – Bhuro Sep 07 '16 at 03:27