如何在Java中合并路径?

How to combine paths in Java?

C#/。NET中是否有System.IO.Path.Combine()的Java等效项? 或任何代码来实现这一目标?

此静态方法将一个或多个字符串组合到路径中。


而不是让所有内容都基于字符串,您应该使用旨在表示文件系统路径的类。

如果您使用的是Java 7或Java 8,则应强烈考虑使用java.nio.file.PathPath.resolve可用于将一个路径与另一个路径或字符串组合。 Paths辅助类也很有用。例如:

1
Path path = Paths.get("foo","bar","baz.txt");

如果需要满足Java-7之前的环境,可以使用java.io.File,如下所示:

1
2
3
File baseDirectory = new File("foo");
File subDirectory = new File(baseDirectory,"bar");
File fileInDirectory = new File(subDirectory,"baz.txt");

如果以后希望将其作为字符串返回,则可以调用getPath()。确实,如果您真的想模仿Path.Combine,则可以编写如下内容:

1
2
3
4
5
6
public static String combine(String path1, String path2)
{
    File file1 = new File(path1);
    File file2 = new File(file1, path2);
    return file2.getPath();
}


在Java 7中,应使用resolve

1
Path newPath = path.resolve(childPath);

尽管NIO2 Path类对于使用不必要的不??同API的File似乎有点多余,但实际上它更优雅,更强大。

请注意,Paths.get()(由其他人建议)没有承受Path的重载,并且执行Paths.get(path.toString(), childPath)resolve()并不相同。从Paths.get()文档:

Note that while this method is very convenient, using it will imply an assumed reference to the default FileSystem and limit the utility of the calling code. Hence it should not be used in library code intended for flexible reuse. A more flexible alternative is to use an existing Path instance as an anchor, such as:

1
2
Path dir = ...
Path path = dir.resolve("file");

resolve的姐妹函数是出色的relativize

1
Path childPath = path.relativize(newPath);


主要的答案是使用File对象。但是Commons IO确实有一个类FilenameUtils可以执行这种操作,例如concat()方法。


自从乔恩(Jon)的原始答案以来,我就已经知道了很长时间,但是我对OP有类似的要求。

通过扩展Jon的解决方案,我提出了以下内容,它将采用一个或多个路径段,而您可以将其扔给它。

用法

1
2
3
Path.combine("/Users/beardtwizzle/");
Path.combine("/","Users","beardtwizzle");
Path.combine(new String[] {"/","Users","beardtwizzle","arrayUsage" });

在这里为其他有类似问题的人编码

1
2
3
4
5
6
7
8
9
10
11
12
public class Path {
    public static String combine(String... paths)
    {
        File file = new File(paths[0]);

        for (int i = 1; i < paths.length ; i++) {
            file = new File(file, paths[i]);
        }

        return file.getPath();
    }
}

平台无关的方法(使用File.separator,即能否工作取决于运行代码的操作系统:

1
2
3
4
5
6
7
8
9
10
java.nio.file.Paths.get(".","path","to","file.txt")
// relative unix path: ./path/to/file.txt
// relative windows path: .\path\to\filee.txt

java.nio.file.Paths.get("/","path","to","file.txt")
// absolute unix path: /path/to/filee.txt
// windows network drive path: \\path\to\file.txt

java.nio.file.Paths.get("C:","path","to","file.txt")
// absolute windows path: C:\path\to\file.txt

为了增强JodaStephen的答案,Apache Commons IO具有FilenameUtils来执行此操作。示例(在Linux上):

1
assert org.apache.commons.io.FilenameUtils.concat("/home/bob","work\\stuff.log") =="/home/bob/work/stuff.log"

它是独立于平台的,可以生成系统所需的任何分隔符。


如果您不需要的只是字符串,则可以使用com.google.common.io.Files

1
Files.simplifyPath("some/prefix/with//extra///slashes" +"file//name")

要得到

1
"some/prefix/with/extra/slashes/file/name"

这在Java 8中也适用:

1
2
Path file = Paths.get("Some path");
file = Paths.get(file +"Some other path");

也许聚会晚了,但是我想分享我对此的看法。我正在使用Builder模式,并允许方便地链接append调用。它可以轻松扩展以支持使用Path对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class Files  {
    public static class PathBuilder {
        private File file;

        private PathBuilder ( File root ) {
            file = root;
        }

        private PathBuilder ( String root ) {
            file = new File(root);
        }

        public PathBuilder append ( File more ) {
            file = new File(file, more.getPath()) );
            return this;
        }

        public PathBuilder append ( String more ) {
            file = new File(file, more);
            return this;
        }

        public File buildFile () {
            return file;
        }
    }

    public static PathBuilder buildPath ( File root ) {
        return new PathBuilder(root);
    }

    public static PathBuilder buildPath ( String root ) {
        return new PathBuilder(root);
    }
}

用法示例:

1
2
3
4
5
6
7
8
File root = File.listRoots()[0];
String hello ="hello";
String world ="world";
String filename ="warez.lha";

File file = Files.buildPath(root).append(hello).append(world)
              .append(filename).buildFile();
String absolute = file.getAbsolutePath();

生成的absolute将包含以下内容:

1
/hello/world/warez.lha

甚至:

1
A:\hello\world\warez.lha

这是处理多个路径部分和边缘条件的解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static String combinePaths(String ... paths)
{
  if ( paths.length == 0)
  {
    return"";
  }

  File combined = new File(paths[0]);

  int i = 1;
  while ( i < paths.length)
  {
    combined = new File(combined, paths[i]);
    ++i;
  }

  return combined.getPath();
}

该解决方案提供了一个接口,用于连接String []数组中的路径片段。它使用java.io.File.File(String parent,String child):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    public static joinPaths(String[] fragments) {
        String emptyPath ="";
        return buildPath(emptyPath, fragments);
    }

    private static buildPath(String path, String[] fragments) {
        if (path == null || path.isEmpty()) {
            path ="";
        }

        if (fragments == null || fragments.length == 0) {
            return"";
        }

        int pathCurrentSize = path.split("/").length;
        int fragmentsLen = fragments.length;

        if (pathCurrentSize <= fragmentsLen) {
            String newPath = new File(path, fragments[pathCurrentSize - 1]).toString();
            path = buildPath(newPath, fragments);
        }

        return path;
    }

然后,您可以执行以下操作:

1
2
String[] fragments = {"dir","anotherDir/","/filename.txt"};
String path = joinPaths(fragments);

返回值:

1
"/dir/anotherDir/filename.txt"