2010-04-21 90 views
20

是否有人知道我可以用来生成规范路径的任何Java库(基本上删除反向引用)。生成规范路径

我需要的东西,将做到以下几点:

原始路径 - >规范路径

/../foo/  -> /foo 
/foo/   -> /foo 
/../../../  ->/
/./foo/./  -> /foo 
//foo//bar  -> /foo/bar 
//foo/../bar -> /bar 

等等

此刻我懒洋洋地依赖于使用:

new File("/", path).getCanonicalPath(); 

但是这解决了这个问题h针对实际的文件系统,并且是同步的。

java.lang.Thread.State: BLOCKED (on object monitor) 
     at java.io.ExpiringCache.get(ExpiringCache.java:55) 
     - waiting to lock <0x93a0d180> (a java.io.ExpiringCache) 
     at java.io.UnixFileSystem.canonicalize(UnixFileSystem.java:137) 
     at java.io.File.getCanonicalPath(File.java:559) 

,我canonicalising没有我的文件系统中的路径,方法的所以只是逻辑将尽我的罚款,因此不需要任何同步。我希望有一个经过良好测试的图书馆,而不是自己写。

+0

支持的输入是相对路径吗?或者这是一个错误条件? – 2010-04-21 14:16:37

+0

'/ foo /../ bar /'应该输出什么? – 2010-04-21 14:17:07

+0

@Joachim:我假设所有的路径都是基于根。在大多数情况下,我只是删除从URL中的路径引用。 – Joel 2010-04-21 14:17:19

回答

18

我想你可以用URI这个类来做到这一点;例如如果路径中不包含需要在URI路径组件中转义的字符,则可以执行此操作。

String normalized = new URI(path).normalize().getPath(); 

如果路径中包含(或可能包含)其他需要转义字符,多参数的构造函数将难逃path参数,并可以提供null为其他参数。

请注意,URI规范化不涉及将文件系统视为文件规范化。但另一方面,当路径中存在符号链接时,规范化的行为与规范化的行为不同。

+0

看起来不错。它仍然需要一点调整(删除前导/../,但它使我在那里的大部分方式,谢谢。 – Joel 2010-04-21 14:46:44

+1

@Joel:你为什么要删除前导'/../'?他们是错的你应该把它们视为一个错误条件,或者你指定所有路径相对于某个点,并且你应该支持它们,但是默默地去除它们听起来像是一个糟糕的主意。 – 2010-04-21 14:57:03

+0

你可能是对的,但我得到各种糟糕的数据我正在清理它,确保所有路径都扎根于/ – Joel 2010-04-21 14:59:26

4

你可以尝试这样的算法:

String collapsePath(String path) { 
    /* Split into directory parts */ 
    String[] directories = path.split("/"); 
    String[] newDirectories = new String[directories.length]; 
    int i, j = 0; 

    for (i=0; i<directories.length; i++) { 
     /* Ignore the previous directory if it is a double dot */ 
     if (directories[i].equals("..") && j > 0) 
      newDirectories[j--] = ""; 
     /* Completely ignore single dots */ 
     else if (! directories[i].equals(".")) 
      newDirectories[j++] = directories[i]; 
    } 

    /* Ah, what I would give for String.join() */ 
    String newPath = new String(); 
    for (i=0; i < j; i++) 
     newPath = newPath + "/" + newDirectories[i]; 
    return newPath; 
} 

这是不完美的;它与目录数量呈线性关系,但确实在内存中创建了副本。

14

使用阿帕奇百科全书IO(一个著名的和经过良好测试库)

public static String normalize(String filename) 

会做你寻找什么。

例子:

String result = FilenameUtils.normalize(myFile.getAbsolutePath()); 
0

的规范路径是依赖于操作系统的哪一种路径是合格的。 这就是为什么Java需要在文件系统上检查它的原因。 所以没有简单的逻辑就可以在不知道操作系统的情况下测试路径。

9

如果你不需要路径规范化但只规范化,在Java 7中,你可以使用java.nio.file.Path.normalize方法。 根据http://docs.oracle.com/javase/7/docs/api/java/nio/file/Path.html

此方法不访问文件系统;该路径可能找不到存在的文件。

如果使用File对象可以使用的方法是这样的:

file.toPath().normalize().toFile() 
-2

我假设你有一个字符串,你想串,你有Java 7的可现在,你的默认文件系统使用 '/' 作为路径分隔符,所以尝试:

String output = FileSystems.getDefault().getPath(input).normalize().toString(); 

你可以试试这个出有:

/** 
* Input   Output 
* /../foo/  -> /foo 
* /foo/  -> /foo 
* /../../../ ->/
* /./foo/./ -> /foo 
* //foo//bar -> /foo/bar 
* //foo/../bar -> /bar 
*/ 
@Test 
public void testNormalizedPath() throws URISyntaxException, IOException { 
    String[] in = new String[]{"/../foo/", "/foo/", "/../../../", "/./foo/./", 
      "//foo/bar", "//foo/../bar", "/", "/foo"}; 
    String[] ex = new String[]{"/foo", "/foo", "/", "/foo", "/foo/bar", "/bar", "/", "/foo"}; 
    FileSystem fs = FileSystems.getDefault(); 
    for (int i = 0; i < in.length; i++) { 
     assertEquals(ex[i], fs.getPath(in[i]).normalize().toString()); 
    } 
}