0

I'm attempting to save a JSON string to a file on the 'External' storage. Specifically the Documents folder. This would should be the storage you could access with a file browser, from gmail, or over USB on your computer.

So I followed the documentation here and came up with this: (note, changed to now create directory first, then append filename. Save now attempts to use MediaScanner)

public static File GetDocumentsPath(String tuningName) {
    // Get the directory for the user's public pictures directory.
    File dir = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_DOWNLOADS).getAbsolutePath());
    if (!dir.mkdirs()) {
        Logy.CallPrint("JSONTuning", "Directory not created");
    }

    File outFile = new File(dir, tuningName);

    return outFile;
}

public static String SaveTuning(Context context, String fileName, String json)
{
    File path;
    if(fileName.contains(".rfts")) {
        path = GetDocumentsPath(fileName);
    } else {
        path = GetDocumentsPath(fileName+".rfts");
    }


    Logy.Print("|||||||||||||||| "+path.getPath());

    try {
        FileOutputStream fileOut = new FileOutputStream(path);
        ObjectOutput strOut = new ObjectOutputStream(fileOut);
        strOut.writeUTF(json);
        strOut.close();
        fileOut.close();

        MediaScannerConnection scanner = new MediaScannerConnection(context, null);
        scanner.connect();
        if(scanner.isConnected())
            scanner.scanFile(path.getPath(), null);
        scanner.disconnect();

        return "Save Successful";
    }
    catch(java.io.IOException e) {
        return e.getMessage();
    }
}

So I logged the path I was getting from GetDocumentsPath. That path would be: /storage/emulated/0/Download/Test.rfts

This does not lead to the file being saved in Documents as far as what I can access via file manager/computer. The fact that the word "emulated" is in there leads me to believe Environment isn't giving me the actual path at all.

I do get the error "/storage/emulated/0/Documents/Test.rfts: open failed: ENOENT (No such file or directory)"

What's needed to get the correct path, and save to, the documents folder in external storage?

As a side note, the way I write the file works perfectly fine for internal storage, as I'm having no issues creating a file with app settings.

Magic Marbles
  • 403
  • 2
  • 5
  • 15

1 Answers1

2

The fact that the word "emulated" is in there leads me to believe Environment isn't giving me the actual path at all.

Yes, it is.

I do get the error "/storage/emulated/0/Documents/Test.rfts: open failed: ENOENT (No such file or directory)"

Possibilities include:

  • The directory does not exist. This is typical with the emulator. Usually, you call mkdirs() to create the directory, just to be safe.

  • You are running on Android 6.0+ device, your targetSdkVersion is 23 or higher, and you did not implement runtime permissions.

Also note that you need to add more code to have your file show up in other apps or via a file manager on a desktop/notebook computer.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Hmmm so I'm running Marshmallow on my tablet. When I go to request permission to write to external storage however, no popup comes up and the request is automatically denied. Elsewhere in my app I request fine location permission with no issue so I'm not sure what gives. – Magic Marbles Nov 30 '16 at 22:24
  • @MagicMarbles: "When I go to request permission to write to external storage however, no popup comes up and the request is automatically denied" -- go to Settings > Apps > (your app) > Permissions and manually grant it. Confirm that your app works. If it does, go back into Settings for your app, uninstall from there, then try a fresh install and see if you can request the permission. – CommonsWare Nov 30 '16 at 22:32
  • Seems like that worked. However even with permission I'm still getting an emulated path. I can write to it and get success back, but nothing shows up in the directory. Besides that, the Nvidia Shield tablet I'm using doesn't even have a Documents folder, so I switched to Download for now. I'll update my question with my new Save function, which includes the MediaScanner scanning for the file. However I'm not sure if this is correct, as nothing is showing up still. – Magic Marbles Nov 30 '16 at 23:26
  • @MagicMarbles: "nothing is showing up still" -- how are you testing this? If you already have the directory open in a file manager, you may need to do a "refresh"/"reload" sort of operation to get it to find out about changes. I recommend using `adb shell ls` to examine the filesystem directly first. If the file still does not show up, then there's a problem in the code. Also, I recommend using the static `scanFile()` or not disconnecting until after the scan is completed. – CommonsWare Nov 30 '16 at 23:28
  • I'm toggling between "use USB for charging" and "use USB for file transfer" on the tablet. I'm browsing the folders from my PC. I swap modes after I write the file, which closes the file explorer in the process so I have to reopen it. Looks like this: http://imgur.com/a/9atoT – Magic Marbles Nov 30 '16 at 23:30
  • I've got to head out to class and won't be back til 11 my time. If you're around tomorrow I'll pick back up on this. Thanks for the help – Magic Marbles Dec 01 '16 at 00:13
  • You should use a file explorer app on your device to begin with. Moreover you do not have to switch between usb modi as MTP protocol is used. – greenapps Dec 01 '16 at 09:03
  • `that, the Nvidia Shield tablet I'm using doesn't even have a Documents folder,`. But then mkdirs would create it and if not it would be reported by your log. And if the directory was there your log would also report that the directory could not be created. Do not blindly call mkdirs. Only if the dir does not exist. You should return a null there instead of continue with code. – greenapps Dec 01 '16 at 09:08
  • The only Dir I attempt to create is one of the pre-defined directories given by Android. And in any case my code attempts to mkdir and if it fails (directory already exists) it simply proceeds to generate the File with the actual filename and path and passes it off to be saved in the directory. This is how Android documentation suggests this be done. Unfortunately the docs don't indicate how to do this in 6.0 which is evidently different from how previous versions saved files. I'm saving a file to an emulated directory path. This file does not show up in the public folders like Downloads. – Magic Marbles Dec 01 '16 at 18:06
  • Also, I'm not using a file explorer on my Nvidia Shield because it doesn't have one. Nor can I download one, as it doesn't hook up with the companies wifi. It just flat out doesn't connect so I have no way to access the app store. – Magic Marbles Dec 01 '16 at 18:09
  • @MagicMarbles: "Unfortunately the docs don't indicate how to do this in 6.0 which is evidently different from how previous versions saved files" -- other than runtime permissions, there are no differences. – CommonsWare Dec 01 '16 at 18:31
  • @MagicMarbles: "This file does not show up in the public folders like Downloads" -- check using `adb shell ls`. If it is there, then replace your `MediaScannerConnection` code with one that uses the `static` `scanFile()` method, as you are disconnecting too early. – CommonsWare Dec 01 '16 at 18:41
  • Changing to the static scanFile fixed it! If you make this into an answer I believe I can mark it as the solution. – Magic Marbles Dec 01 '16 at 19:35
  • @MagicMarbles: I already linked to material describing the `MediaScannerConnection` issue in the answer -- it's been there since the beginning. I updated that answer to include a code snippet. – CommonsWare Dec 01 '16 at 19:55