In my app, users pick files. Internally, I store information about the file, which I key based on the file path. Next time that file is used, I do stuff with the stored information. Trouble is I instantiate my files with:
File file1 = new File(Environment.getExternalStorageDirectory() + "/test.txt");
And then, on a particular JB device, file1.getCanonicalPath() gives: "/storage/emulated/0/test.txt".
The trouble is that when other apps launch my app with a file path in an Intent, the paths they send tend to look like: "/mnt/sdcard/test.txt".
Is there a smart strategy to disambiguate these two paths? Possibly I should be instantiating my files differently?
Edit:
The trouble is, the two canaonical paths for the two files are not equal. For the below, cp1=="mnt/sdcard/test/txt"
and cp2=="/storage/emulated/0/text/txt"
:
File file1 = new File("/mnt/sdcard/test.txt");
File file2 = new File("/storage/emulated/0/test.txt");
String cp1 = file1.getCanonicalPath();
String cp2 = file2.getCanonicalPath();
The canonical path is always an absolute and unique path. If String pathname is used to create a file object, it simply returns the pathname. This method first converts this pathname to absolute form if needed. To do that it will invoke the getAbsolutePath() Method and then maps it to its unique form.
First, the only correct way to get the external path is using the getExternalStorageDirectory
and other getExternalStorageXXX
in Android.
Android will firstly try to resolve two system variable:
String rawExternalStorage = System.getenv(ENV_EXTERNAL_STORAGE);
String rawEmulatedStorageTarget = System.getenv(ENV_EMULATED_STORAGE_TARGET);
while the ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE"
and ENV_EMULATED_STORAGE_TARGET = "EMULATED_STORAGE_TARGET"
. If the EMULATED_STORAGE_TARGET
variable is set, it means the device has emulated storage then the storage path will be EMULATED_STORAGE_TARGET
.(After Android 4.2, it support multiple-user external storage, then there would be a /0 or 0 after the path) But if it is not set and EXTERNAL_STORAGE
is set, the path will be EXTERNAL_STORAGE
. If both of them are not set, the path will be /storage/sdcard0
by default. So different devices may contain different paths for external storage.
As External Storage Technical Information says, you can customize the storage of the device by setting up the init.rc file. For example in the default goldfish one:
export EXTERNAL_STORAGE /mnt/sdcard
mkdir /mnt/sdcard 0000 system system
symlink /mnt/sdcard /sdcard
If you use getExternalStorageDirectory
you will get /mnt/sdcard
, but /sdcard
is a symbolic link to that directory.
So in your case, the init.rc may contain:
export EMULATED_STORAGE_TARGET /storage/emulated
symlink /storage/emulated/0 /mnt/sdcard
So they are not ambiguous, they are actually same.
I think the getCanonicalPath() might work for the vast majority of your use cases.
A canonical pathname is both absolute and unique. The precise definition of canonical form is system-dependent. This method first converts this pathname to absolute form if necessary, as if by invoking the getAbsolutePath() method, and then maps it to its unique form in a system-dependent way. This typically involves removing redundant names such as "." and ".." from the pathname, resolving symbolic links (on UNIX platforms), and converting drive letters to a standard case (on Microsoft Windows platforms).
Every pathname that denotes an existing file or directory has a unique canonical form. Every pathname that denotes a nonexistent file or directory also has a unique canonical form. The canonical form of the pathname of a nonexistent file or directory may be different from the canonical form of the same pathname after the file or directory is created. Similarly, the canonical form of the pathname of an existing file or directory may be different from the canonical form of the same pathname after the file or directory is deleted.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With