Tham gia các đường dẫn trong Java


99

Trong Pythontôi có thể tham gia hai con đường với os.path.join:

os.path.join("foo", "bar") # => "foo/bar"

Tôi đang cố gắng đạt được điều tương tự trong Java, mà không cần lo lắng nếu OSUnix, Solarishoặc Windows:

public static void main(String[] args) {
    Path currentRelativePath = Paths.get("");
    String current_dir = currentRelativePath.toAbsolutePath().toString();
    String filename = "data/foo.txt";
    Path filepath = currentRelativePath.resolve(filename);

    // "data/foo.txt"
    System.out.println(filepath);

}

Tôi đã mong đợi điều đó Path.resolve( )sẽ tham gia vào thư mục hiện tại của tôi /home/user/testvới data/foo.txtviệc tạo ra /home/user/test/data/foo.txt. Tôi đang làm gì sai?


1
đây có thể là thứ mà tôi không nhìn thấy. Đường dẫn hiện tại của bạn là "". Đường dẫn thứ hai của bạn là "data / foo.txt". Có lẽ vấn đề của bạn là bạn dường như in một đối tượng đường dẫn thay vìfilepath.toString()
cjds

2
Sử dụngnew File(parent, child)
saka1029 25/12/15

Câu trả lời:


99

Mặc dù giải pháp ban đầu để lấy thư mục hiện tại bằng cách sử dụng empty Stringhoạt động. Nhưng nên sử dụng thuộc user.dirtính cho thư mục hiện tại và user.homecho thư mục chính.

Path currentPath = Paths.get(System.getProperty("user.dir"));
Path filePath = Paths.get(currentPath.toString(), "data", "foo.txt");
System.out.println(filePath.toString());

đầu ra:

/Users/user/coding/data/foo.txt

Từ Tài liệu lớp Đường dẫn Java :

Đường dẫn được coi là một đường dẫn trống nếu nó chỉ chứa một phần tử tên empty. Truy cập tệp bằng empty path is equivalent to accessing the default directoryhệ thống tệp.


Tại sao Paths.get("").toAbsolutePath()hoạt động

Khi một chuỗi rỗng được chuyển đến Paths.get(""), Pathđối tượng trả về sẽ chứa đường dẫn trống. Nhưng khi chúng ta gọi Path.toAbsolutePath(), nó sẽ kiểm tra xem độ dài đường dẫn có lớn hơn 0 hay không, nếu không, nó sử dụng thuộc tính user.dirhệ thống và trả về đường dẫn hiện tại.

Đây là mã triển khai hệ thống tệp Unix: UnixPath.toAbsolutePath ()


Về cơ bản, bạn cần tạo lại Pathphiên bản sau khi bạn giải quyết đường dẫn thư mục hiện tại.

Ngoài ra, tôi sẽ đề nghị sử dụng File.separatorCharcho mã độc lập nền tảng.

Path currentRelativePath = Paths.get("");
Path currentDir = currentRelativePath.toAbsolutePath(); // <-- Get the Path and use resolve on it.
String filename = "data" + File.separatorChar + "foo.txt";
Path filepath = currentDir.resolve(filename);

// "data/foo.txt"
System.out.println(filepath);

Đầu ra:

/Users/user/coding/data/foo.txt

Không phải là tôi, có thể ai đó nghĩ rằng làm việc trên dây và separatorCharkém hơn so với một số "mức trừu tượng cao hơn", một cái gì đó trông giống nhưPathBuilder(currentRelativePath).append("data").append("foo.txt")
jingyu9575

22

Paths#get(String first, String... more) Những trạng thái,

Chuyển đổi một chuỗi đường dẫn hoặc một chuỗi các chuỗi khi được nối với nhau tạo thành một chuỗi đường dẫn, thành a Path.

...

Một Pathđại diện cho một đường dẫn trống được trả về nếu đầu tiên là chuỗi trống và nhiều hơn không chứa bất kỳ chuỗi nào không trống.

Để có được thư mục người dùng hiện tại, bạn chỉ cần sử dụng System.getProperty("user.dir").

Path path = Paths.get(System.getProperty("user.dir"), "abc.txt");
System.out.println(path);

Hơn nữa, getphương thức sử dụng đối số độ dài thay đổi của String, đối số này sẽ được sử dụng để cung cấp các chuỗi đường dẫn tiếp theo. Vì vậy, để tạo Pathcho /test/inside/abc.txtbạn phải sử dụng nó theo cách sau,

Path path = Paths.get("/test", "inside", "abc.txt");

11

Không phải là một phương pháp cụ thể.

Nếu bạn sử dụng java 8 trở lên, bạn có 2 lựa chọn:

a) Sử dụng java.util.StringJoiner

StringJoiner joiner = new StringJoiner(File.pathSeparator); //Separator
joiner.add("path1").add("path2");
String joinedString = joiner.toString();

b) Sử dụng String.join(File.pathSeparator, "path1", "path2");

Nếu bạn sử dụng java 7 trở xuống, bạn có thể sử dụng thư viện commons-lang từ các commons apache. Lớp StringUtils có một phương thức để nối các chuỗi bằng dấu phân cách.

c) StringUtils.join(new Object[] {"path1", "path2"}, File.pathSeparator);

Chú thích phụ: Bạn có thể sử dụng dấu phân cách đường dẫn linux "/" cho windows (Chỉ cần nhớ rằng các đường dẫn tuyệt đối là một cái gì đó giống như "/ C: / mydir1 / mydir2". Sử dụng luôn "/" rất hữu ích nếu bạn sử dụng các giao thức như tệp: //


StringJoiner trở tôi/home/user/test:foo.txt
cybertextron

Những lựa chọn mà bạn biết không phải là những lựa chọn duy nhất tồn tại. Ví dụ, người ta có thể sử dụng StringBuilder thay vì trình kết hợp. Và trên thực tế, việc triển khai của bạn dựa trên Chuỗi chứ không phải tệp / đường dẫn là khá ngây thơ và sẽ dẫn đến các vấn đề trong nhiều trường hợp.
XenoRo

2
File.separatorlàm việc cho tôi thay vìFile.pathSeparator
Evan Siroky

sử dụng Pathes.get ("path1", "path2"). toAbsolutePath (). toString ()
Erdinc Ay

5

Cách cơ bản nhất là:

Path filepath = Paths.get("foo", "bar");

Bạn không bao giờ nên viết Paths.get(""). Tôi ngạc nhiên rằng nó hoạt động ở tất cả. Nếu bạn muốn tham chiếu đến thư mục hiện tại một cách rõ ràng, hãy sử dụng Paths.get(System.getProperty("user.dir")). Nếu bạn muốn thư mục chính của người dùng, hãy sử dụng Paths.get(System.getProperty("user.home")).

Bạn cũng có thể kết hợp các phương pháp:

Path filepath = Paths.get(
    System.getProperty("user.home"), "data", "foo.txt");

1

Cách đáng tin cậy nhất, độc lập với nền tảng để tham gia các đường dẫn trong Java là sử dụng Path::resolve(như đã lưu ý trong JavaDoc for Paths::get). Đối với một mảng Chuỗi có độ dài tùy ý đại diện cho các phần của một đường dẫn, chúng có thể được nối với nhau bằng Java Stream:

private static final String[] pieces = {
    System.getProperty("user.dir"),
    "data",
    "foo.txt"};
public static void main (String[] args) {
    Path dest = Arrays.stream(pieces).reduce(
    /* identity    */ Paths.get(""),
    /* accumulator */ Path::resolve,
    /* combiner    */ Path::resolve);
    System.out.println(dest);
}

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.