代码之家  ›  专栏  ›  技术社区  ›  Joel

生成规范路径

  •  21
  • Joel  · 技术社区  · 16 年前

    我需要一些可以做以下事情的东西:

    原始路径->标准路径

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

    等。。。

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

    但这会根据实际的文件系统解析路径,并且是同步的。

       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)
    

    我正在规范化的路径在我的文件系统中不存在,所以只要方法的逻辑就可以了,因此不需要任何同步。我希望有一个经过良好测试的图书馆,而不是自己写。

    6 回复  |  直到 13 年前
        1
  •  21
  •   Stephen C    7 年前

    我想你可以用 URI 类来做这个;e、 如果路径中没有需要在URI路径组件中转义的字符,那么可以这样做。

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

    如果路径包含(或可能包含)需要转义的字符,则多参数构造函数将转义 path null 对于其他论点。

    1. 以上通过将文件路径视为相对URI来规范化文件路径。如果要规范化整个URI。。。包括(可选)方案、权限和其他组件,不调用 getPath() !

        2
  •  17
  •   tom91136    11 年前

    使用 (一个著名的、久经考验的图书馆)

    public static String normalize(String filename)
    

    String result = FilenameUtils.normalize(myFile.getAbsolutePath());
    
        3
  •  12
  •   Andrej Golcov    11 年前

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

    如果使用文件对象,可以使用以下内容:

    file.toPath().normalize().toFile()
    
        4
  •  4
  •   Haldean Brown    16 年前

    你可以尝试这样的算法:

    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;
    }
    

    它并不完美;它与目录数成线性关系,但确实在内存中复制了一个。

        5
  •  0
  •   Roland    13 年前

    哪种路径被限定为规范路径取决于操作系统。 这就是为什么Java需要在文件系统上检查它。 因此,在不知道操作系统的情况下,没有简单的逻辑来测试路径。

        6
  •  0
  •   JonAar Livernois    6 年前

    因此,虽然规范化可以做到这一点,但这里有一个过程,它公开的javaapi比简单地调用 Paths.normalize()

    我的工作代码文件是

    myproject/src/JavaCode.java

    位于myproject/src/中。我的文件在

    ../../data/myfile.txt

    我正在测试运行JavaCode.java代码的程序

    public static void main(String[] args) { 
        findFile("../../data","myfile.txt");
        System.out.println("Found it.");
    }
    public static File findFile(String inputPath, String inputFile) {
        File dataDir = new File("").getAbsoluteFile(); // points dataDir to working directory
        String delimiters = "" + '\\' + '/';           // dealing with different system separators
        StringTokenizer st = new StringTokenizer(inputPath, delimiters);
        while(st.hasMoreTokens()) {
            String s = st.nextToken();
            if(s.trim().isEmpty() || s.equals(".")) 
                continue;
            else if(s.equals("..")) 
                dataDir = dataDir.getParentFile();
            else {
                dataDir = new File(dataDir, s);
                if(!dataDir.exists())
                    throw new RuntimeException("Data folder does not exist.");
            }
        }
        return new File(dataDir, inputFile);    
    }
    

    在指定位置放置了一个文件后,应该打印“Found it”

        7
  •  -1
  •   dlamblin    11 年前

    我假设你有字符串,你想要字符串,你现在有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());
        }
    }
    
    推荐文章