20

My app downloads and unzips a file in a specific folder:

output = new FileOutputStream(realpath, true);
output.write(buffer, 0, bytesRead);

ZipFile zipFile = new ZipFile(realpath);

With the new introduced ACTION_OPEN_DOCUMENT_TREE Intent, I would like to offer the user to choose that folder.

When testing the values received in my onActivityResult, I get a Path like /tree/primary:mynewfolder, which is not the physical real path like /sdcard/mynewfolder.

Uri treeUri = data.getData();
String sPath = treeUri.getPath();
Log.v("Path from Tree ", sPath);

My unzip method need the real path:

ZipFile zipFile = new ZipFile(realpath);

How do I get the real path like /sdcard/mynewfolder from the provided URI in Lollipop (API 21 & 22)?

Spikatrix
  • 20,225
  • 7
  • 37
  • 83
mcfly soft
  • 11,289
  • 26
  • 98
  • 202

3 Answers3

30

Process of getting real Path from URI is same as before, but with a little addition:

Uri uri = data.getData();
Uri docUri = DocumentsContract.buildDocumentUriUsingTree(uri, 
                        DocumentsContract.getTreeDocumentId(uri));
String path = getPath(this, docUri);

The gist of getPath() method with intermediate methods can be found here: getPath()

Asif Mujteba
  • 4,596
  • 2
  • 22
  • 38
  • Thanks a lot , thats what I was looking for. Perfect ! If you like you can answer also this similar question and I will accept. http://stackoverflow.com/questions/29775068/open-a-sqlite-database-when-choosing-folder-with-action-open-document-tree – mcfly soft Apr 22 '15 at 16:00
  • My Pleasure, Glad that helped, I have posted the answer there as well! – Asif Mujteba Apr 22 '15 at 16:40
  • 4
    It doesn't seem to work about SD-card paths. How did it work for you? For me it crashes, as it returned null (yet it identified that it's an external storage type). – android developer Jul 27 '15 at 20:14
  • @androiddeveloper: If you inspect getPath() code you will see that there is a todo comment: "// TODO handle non-primary volumes". Unfortunately it looks like it wont work for exteral sd card (or any other secondary storage). – sdf3qrxewqrxeqwxfew3123 Aug 27 '15 at 05:15
  • @lenrok258 That's too bad. But, I've found this one: https://github.com/jeisfeld/Augendiagnose/blob/master/AugendiagnoseLib/src/de/jeisfeld/augendiagnoselib/util/imagefile/FileUtil.java . The developer said that even though the repo is GNU licensed, it's ok to use the file-related stuff. – android developer Aug 28 '15 at 09:29
  • 2
    @androiddeveloper Did you find any solution for external SD card? I'm facing the similar issue. Cannot get the real path of selected folder in external SD card. – TOP Oct 16 '15 at 11:17
  • @Sunshinetpu I've found a way, but it's a workaround. Create a unique file on your app's external storage path, and try to find it through DocumentFile. If you've found it, it's the same external storage path, and you can use the same one as used for the external storage. – android developer Oct 16 '15 at 20:12
  • @androiddeveloper I think it is a very good idea. Thank you very much! I will try it. – TOP Oct 17 '15 at 02:50
  • You can also check the link I've provided they do it differently. Sadly, both ways are workarounds. Please, consider upvoting there SD-cards related posts : https://code.google.com/p/android-developer-preview/issues/detail?id=2676 https://code.google.com/p/android-developer-preview/issues/detail?id=3078 https://code.google.com/p/android/issues/detail?id=161224 https://code.google.com/p/android/issues/detail?id=185220 https://code.google.com/p/android/issues/detail?id=189494 – android developer Oct 17 '15 at 09:28
  • @androiddeveloper Could you please post that workaround for locations for an external SD card as an answer? Thank you! – Spikatrix Jun 16 '18 at 06:00
  • @CoolGuy I think I wrote it here: https://stackoverflow.com/a/25612858/878126 . Please let me know if it helps. I also wonder if it can work with USB OTG, so please let me know this too. – android developer Jun 16 '18 at 06:31
  • @androiddeveloper But your code there returns _all_ the external storages, right? I'm looking on how to convert my uri which points to a path on the SD Card into the real path. Preferably, what do I insert in the `// TODO handle non-primary volumes` in the `getPath` method shown in this answer? – Spikatrix Jun 16 '18 at 06:56
  • 2
    @CoolGuy Oh. So maybe this could help: https://www.programcreek.com/java-api-examples/index.php?source_dir=Augendiagnose-master/AugendiagnoseIdea/augendiagnoseLib/src/main/java/de/jeisfeld/augendiagnoselib/util/imagefile/FileUtil.java . Or this: https://stackoverflow.com/a/36162691/878126 . Search for `getFullPathFromTreeUri` . Make it public and try it. If it works, please post the answer here. I shouldn't, because I don't have an SD card so I can't test it myself. – android developer Jun 16 '18 at 07:15
  • 1
    @androiddeveloper Thanks a lot! [Anonymous's answer](https://stackoverflow.com/a/36162691/3049655) worked! That was exactly what I was after – Spikatrix Jun 16 '18 at 08:15
  • @CoolGuy Can you please try it with USB OTG ? I wonder if this works too. – android developer Jun 16 '18 at 08:29
  • @androiddeveloper It returns `"/"` for me with a OTG USB no matter what folder I select in the OTG drive. So, it doesn't work. BTW, my phone isn't rooted if it matters – Spikatrix Jun 16 '18 at 08:54
  • @CoolGuy I see. Thank you – android developer Jun 16 '18 at 09:44
1

Apparently I need reputation to Comment or edit improves Minute V answer. since I guess it's still relevant for people who don't want external libraries or have retrocompatability.

The path you get from just the Uri should be relative to the Environment.getExternalStorageDirectory().getPath(). from what I gather it will have some ":" to split the info on the link.

You just have to split the link and take the last value in the array to get the relative path. Then you just use Environment.getExternalStorageDirectory().getPath()and add a "/" and then add your path.

Here is the code I used:

            Uri uri = resultData.getData();
            String [] pathsections = resultData.getData().getPath().split(":");
            path  = Environment.getExternalStorageDirectory().getPath() + "/" + pathsections[pathsections.length-1];

As you can see, there should be no need to do all does if's and Environment.getExternalStorageDirectory().getPath() should get you the path on a physical device too so you won't have to break your head around hard coding the path.

KingPeter
  • 23
  • 5
0

No need checking android version..

public static string GetRealPath(DocumentFile treeUri)
        {
            if (treeUri == null)
                return "";
            var path1 = treeUri.Uri.Path;
            if (path1.StartsWith("/tree/"))
            {
                var path2 = path1.Remove(0, "/tree/".Length);
                if (path2.StartsWith("primary:"))
                {
                    var primary = path2.Remove(0, "primary:".Length);
                    if (primary.Contains(':'))
                    {
                        
                        var storeName = "/storage/emulated/0/";
                        var last = path2.Split(':').LastOrDefault();
                        var realPath = storeName + last;
                        return realPath;
                    }
                }
                else
                {
                    if (path2.Contains(':'))
                    {
                        var path3 = path2.Split(':').FirstOrDefault();
                        var storeName = path3;
                        var last = path2.Split(':').LastOrDefault();
                        var realPath = "/" + storeName + "/" + last;
                        return realPath;
                    }
                }
            }
            return path1;
        }
Minute V
  • 25
  • 3