Làm cách nào để kết hợp các đường dẫn trong Java?


350

Có tương đương với Java không System.IO.Path.Combine() trong C # /. NET không? Hoặc bất kỳ mã để thực hiện điều này?

Phương thức tĩnh này kết hợp một hoặc nhiều chuỗi thành một đường dẫn.


1
Câu hỏi SO này có thể giúp đỡ.
Jim Blizard

Câu trả lời:


407

Thay vì giữ mọi thứ dựa trên chuỗi, bạn nên sử dụng một lớp được thiết kế để thể hiện đường dẫn hệ thống tệp.

Nếu bạn đang sử dụng Java 7 hoặc Java 8, bạn nên cân nhắc sử dụng java.nio.file.Path; Path.resolvecó thể được sử dụng để kết hợp một đường dẫn với một đường dẫn khác hoặc với một chuỗi. Lớp Pathsngười trợ giúp cũng hữu ích. Ví dụ:

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

Nếu bạn cần phục vụ cho các môi trường tiền Java-7, bạn có thể sử dụng java.io.File, như thế này:

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

Nếu bạn muốn nó trở lại như một chuỗi sau này, bạn có thể gọi getPath(). Thật vậy, nếu bạn thực sự muốn bắt chước Path.Combine, bạn có thể viết một cái gì đó như:

public static String combine(String path1, String path2)
{
    File file1 = new File(path1);
    File file2 = new File(file1, path2);
    return file2.getPath();
}

10
Coi chừng những con đường tuyệt đối. Phiên bản .NET sẽ trả về path2(bỏ qua path1) nếu path2là một đường dẫn tuyệt đối. Phiên bản Java sẽ bỏ phần đầu /hoặc \ và coi nó như một đường dẫn tương đối.
vây

23
@Matthew - vì một thư mục là một tập tin. Đó là tệp có nội dung xác định con của thư mục đó, vị trí của chúng trên đĩa, quyền, v.v.
Dónal

7
@Hugo: Vậy nó lãng phí cả hai đối tượng ? Gây sốc! Nhìn có vẻ khá sạch đối với tôi, thành thật mà nói ... nó giữ logic cho các tên tệp tương đối nơi nó thuộc về, trong lớp Tệp.
Jon Skeet

1
@modosansreves: Nhìn vào File.getCanonicalPath.
Jon Skeet

1
@SargeBorsch: Vâng C # chỉ là một ngôn ngữ. Bạn có thể dễ dàng tạo tương đương của riêng bạn Filetrong C # nếu bạn muốn. (Tôi cho rằng bạn có nghĩa là sự tồn tại của Filemột lợi ích, mà tôi đồng ý.)
Jon Skeet

118

Trong Java 7, bạn nên sử dụng resolve:

Path newPath = path.resolve(childPath);

Mặc dù lớp Đường dẫn NIO2 có vẻ hơi dư thừa đối với Tệp có API khác nhau không cần thiết, nhưng thực tế nó lại thanh lịch và mạnh mẽ hơn một cách tinh tế.

Lưu ý rằng Paths.get()(như được đề xuất bởi người khác) không bị quá tải Path, và thực hiện Paths.get(path.toString(), childPath)KHÔNG giống như resolve(). Từ các Paths.get()tài liệu :

Lưu ý rằng mặc dù phương thức này rất thuận tiện, nhưng sử dụng nó sẽ ngụ ý một tham chiếu giả định đến Hệ thống tệp mặc định và giới hạn tiện ích của mã gọi. Do đó, nó không nên được sử dụng trong mã thư viện dành cho tái sử dụng linh hoạt. Một cách khác linh hoạt hơn là sử dụng một thể hiện Đường dẫn hiện có làm neo, chẳng hạn như:

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

Chức năng chị em resolvelà tuyệt vời relativize:

Path childPath = path.relativize(newPath);

42

Câu trả lời chính là sử dụng các đối tượng File. Tuy nhiên, Commons IO có một lớp FilenameUtils có thể thực hiện loại điều này, chẳng hạn như phương thức concat () .



Nếu bạn đang làm việc với một cái gì đó như JSF, bạn chắc chắn muốn giữ nó dựa trên Chuỗi vì tất cả các Đường dẫn bạn sẽ nhận được sẽ dựa trên Chuỗi.
DanielK 14/07/2015

17

Tôi biết đã lâu rồi kể từ câu trả lời ban đầu của Jon, nhưng tôi có một yêu cầu tương tự với OP.

Bằng cách mở rộng giải pháp của Jon, tôi đã đưa ra cách sau, việc này sẽ lấy một hoặc nhiều đoạn đường dẫn có nhiều đoạn đường mà bạn có thể ném vào nó.

Sử dụng

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

Mã ở đây cho những người khác có vấn đề tương tự

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

12

cách tiếp cận độc lập với nền tảng (sử dụng File.separator, tức là sẽ hoạt động tùy thuộc vào hệ điều hành nơi mã đang chạy:

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

11

Để nâng cao câu trả lời của JodaStephen, Apache Commons IO có FilenameUtils thực hiện điều này. Ví dụ (trên Linux):

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

Đó là nền tảng độc lập và sẽ tạo ra bất kỳ thiết bị phân tách nào mà hệ thống của bạn cần.


2

Đây là một giải pháp xử lý nhiều phần đường dẫn và điều kiện cạnh:

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

2

Nếu bạn không cần nhiều hơn chuỗi, bạn có thể sử dụng com.google.common.io.Files

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

để có được

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

1

Có lẽ đến bữa tiệc muộn, nhưng tôi muốn chia sẻ về việc này. Tôi đang sử dụng mẫu Builder và cho phép appendcác cuộc gọi được xâu chuỗi thuận tiện . Nó có thể dễ dàng được mở rộng để hỗ trợ làm việc với Pathcác đối tượng là tốt.

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

Ví dụ về cách sử dụng:

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();

Kết quả absolutesẽ chứa một cái gì đó như:

/hello/world/warez.lha

hoặc thậm chí có thể:

A:\hello\world\warez.lha

1

Điều này cũng hoạt động trong Java 8:

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

0

Giải pháp này cung cấp giao diện để nối các đoạn đường dẫn từ mảng String []. Nó sử dụng java.io.File.File (Chuỗi cha, chuỗi con) :

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

Sau đó, bạn có thể làm:

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

Trả về:

"/dir/anotherDir/filename.txt"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.