Android:消除文件路径的歧义

时间:2013-04-05 18:53:17

标签: android

在我的应用中,用户选择文件。在内部,我存储有关文件的信息,我根据文件路径键入该文件。下次使用该文件时,我会处理存储的信息。麻烦的是我用以下方式实例化我的文件:

File file1 = new File(Environment.getExternalStorageDirectory() + "/test.txt");

然后,在特定的JB设备上,file1.getCanonicalPath()给出:“/ storage_emulated/0 / test.txt”。

问题在于,当其他应用程序在Intent中使用文件路径启动我的应用程序时,它们发送的路径往往看起来像:“/ mnt /sdcard / test.txt”。

是否有明智的策略消除这两条路径的歧义?可能我应该以不同方式实例化我的文件?

编辑:

麻烦的是,两个文件的两个canaonical路径不相等。对于以下内容,cp1=="mnt/sdcard/test/txt"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();

4 个答案:

答案 0 :(得分:5)

首先,获取外部路径的唯一正确方法是使用Android中的getExternalStorageDirectory和其他getExternalStorageXXX

Android将首先尝试解析两个系统变量:

String rawExternalStorage = System.getenv(ENV_EXTERNAL_STORAGE);
String rawEmulatedStorageTarget = System.getenv(ENV_EMULATED_STORAGE_TARGET);

ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE"ENV_EMULATED_STORAGE_TARGET = "EMULATED_STORAGE_TARGET"。如果设置了EMULATED_STORAGE_TARGET变量,则表示设备已模拟存储,然后存储路径为EMULATED_STORAGE_TARGET。(在Android 4.2之后,它支持多用户外部存储,那么将有一个/ 0或路径后面的0)但是如果未设置并设置EXTERNAL_STORAGE,则路径将为EXTERNAL_STORAGE。如果未设置它们,则默认情况下路径为/storage/sdcard0。因此,不同的设备可能包含不同的外部存储路径。

External Storage Technical Information所述,您可以通过设置init.rc文件来自定义设备的存储。例如在默认的金鱼中:

export EXTERNAL_STORAGE /mnt/sdcard
mkdir /mnt/sdcard 0000 system system
symlink /mnt/sdcard /sdcard

如果您使用getExternalStorageDirectory,则会获得/mnt/sdcard,但/sdcard是指向该目录的符号链接。

因此,在您的情况下,init.rc可能包含:

export EMULATED_STORAGE_TARGET /storage/emulated
symlink /storage/emulated/0 /mnt/sdcard

所以他们并不含糊,他们实际上是一样的。

我认为getCanonicalPath()可能适用于绝大多数用例。

  

规范路径名既是绝对路径名也是唯一路径名。准确的   规范形式的定义是系统依赖的。这个方法首先   如有必要,将此路径名转换为绝对形式,就像使用   调用getAbsolutePath()方法,然后将其映射到其唯一   以系统相关的方式形成。这通常涉及删除   冗余名称,如“。”和路径名中的“..”,解决   符号链接(在UNIX平台上),并将驱动器号转换为   标准案例(在Microsoft Windows平台上)。

     

表示现有文件或目录的每个路径名都具有唯一性   规范形式。表示不存在的文件或的每个路径名   目录也有一个独特的规范形式。规范的形式   不存在的文件或目录的路径名可能与   文件或目录之后的相同路径名的规范形式   创建。类似地,现有路径名的规范形式   文件或目录可能与规范形式不同   删除文件或目录后的路径名。

答案 1 :(得分:2)

对此可能没有简单的解决方案。问题是显然文件系统中有两个不同的挂载点实际指向同一位置。 File.getCanonicalPath()只能解析符号链接,但不能解析不同的挂载点。

例如在我的Nexus 4上这段代码:

File file1 = new File(Environment.getExternalStorageDirectory() + "/Android");
System.out.println("file 1: " + file1.getCanonicalPath());
File file2 = new File("/sdcard/Android");
System.out.println("file 2: " + file2.getCanonicalPath());

打印

file 1: /storage/emulated/0/Android
file 2: /storage/emulated/legacy/Android

我使用此代码执行“mount”并打印输出:

Process exec = Runtime.getRuntime().exec("mount");
InputStream in = exec.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
while (true) {
    String line = br.readLine();
    if (line == null)
        break;
    System.out.println(line);
}
in.close();

相关输出是:

/dev/fuse /storage/emulated/0 fuse rw,nosuid,nodev,relatime,user_id=1023,group_id=1023,default_permissions,allow_other 0 0
/dev/fuse /storage/emulated/legacy fuse rw,nosuid,nodev,relatime,user_id=1023,group_id=1023,default_permissions,allow_other 0 0

答案 2 :(得分:0)

看一下答案here。它也使用规范路径,但以稍微不同的方式可能对你有用

答案 3 :(得分:0)

在较新的Android版本中,SD存储可从多个路径获得,例如:

/storage/emulated/0
/storage/emulated/legacy (root account most of the time)
/sdcard
/data/media

如果你检查这些路径所在的设备,有些设备在不同的设备上(因为保险丝'虚拟文件系统),因此他们的规范路径不会导致相同的文件路径,即使它们实际上是相同的文件。

此外,似乎在Marshmallow上,事情变得更糟,甚至/ sys(完整的重定向/链接)下的文件路径都没有正确报告,并且getCanonicalPath()返回原始路径而不是实际的规范路径。

虽然给定文件路径上的ls -l(或readlink)将显示实际的规范路径,但API不再起作用。不幸的是,运行readlink或ls -l非常慢(当shell已经运行时平均为130ms),与已经很慢但速度更快的getCanonicalPath()相比,这很可惜。

结论,getCanonicalPath已被破坏并且一直被破坏。