Sự khác biệt giữa getPath (), getAbsolutePath () và getCanonicalPath () trong Java là gì?


583

Sự khác biệt giữa những gì getPath(), getAbsolutePath()getCanonicalPath()trong Java?

Và khi nào tôi sử dụng mỗi một?


Đừng quên Path.toAbsolutePath().normalize()đó là một nền tảng tốt giữa con đường chính tắc (thực tế) và con đường tuyệt đối một mình.
eckes

Câu trả lời:


625

Hãy xem xét các tên tệp này:

C:\temp\file.txt - Đây là một con đường, một con đường tuyệt đối và một con đường kinh điển.

.\file.txt- Đây là một con đường. Đó không phải là một con đường tuyệt đối hay một con đường kinh điển.

C:\temp\myapp\bin\..\\..\file.txt- Đây là một con đường và một con đường tuyệt đối. Đó không phải là một con đường kinh điển.

Một con đường kinh điển luôn luôn là một con đường tuyệt đối.

Chuyển đổi từ một đường dẫn đến một con đường kinh điển làm cho nó tuyệt đối (thường tack vào thư mục làm việc hiện tại nên ví dụ như ./file.txttrở thành c:/temp/file.txt). Đường dẫn chính tắc của một tệp chỉ "làm sạch" đường dẫn, loại bỏ và giải quyết các công cụ như ..\và giải quyết các liên kết tượng trưng (trên unixes).

Cũng lưu ý ví dụ sau với nio.Paths:

String canonical_path_string = "C:\\Windows\\System32\\";
String absolute_path_string = "C:\\Windows\\System32\\drivers\\..\\";

System.out.println(Paths.get(canonical_path_string).getParent());
System.out.println(Paths.get(absolute_path_string).getParent());

Mặc dù cả hai đường dẫn đều chỉ đến cùng một vị trí, nhưng đầu ra sẽ khá khác nhau:

C:\Windows
C:\Windows\System32\drivers

11
FWIW, đây không phải C:\temp\file.txtlà một đường dẫn chính tắc - thư mục tạm thời có thể là liên kết mềm hệ thống tệp hoặc liên kết cứng (đường nối trong NTFS) và tệp file.txt có thể là liên kết mềm. Tôi không biết hệ thống tập tin có thể phân biệt các liên kết cứng đến tập tin.
Lawrence Dol

1
đường dẫn không thực sự xem xét những vấn đề hoặc sự tồn tại của bất kỳ thành phần nào, chỉ có cú pháp của nó.
thoát-llc

Nó, đường dẫn chính tắc (không giống như đường dẫn chuẩn hóa) không đánh vào hệ thống tệp.
eckes

1
Về cơ bản, tôi không thể thấy một lý do tại sao người ta nên sử dụng getAbsolutePath()thay vì getCanonicalPath(). Nó thậm chí trông tốt hơn bởi vì một trong những kinh điển tự động giải quyết những ../phần đó.
Scadge

Đừng quên rằng getCanonicalPathném một IOExceptionlúc getAbsolutePaththì không, nếu đây là một sự cân nhắc.
Giỏ hàng bị bỏ rơi

129

Cách tốt nhất mà tôi đã tìm thấy để cảm nhận những thứ như thế này là thử chúng:

import java.io.File;
public class PathTesting {
    public static void main(String [] args) {
        File f = new File("test/.././file.txt");
        System.out.println(f.getPath());
        System.out.println(f.getAbsolutePath());
        try {
            System.out.println(f.getCanonicalPath());
        }
        catch(Exception e) {}
    }
}

Đầu ra của bạn sẽ giống như:

test\..\.\file.txt
C:\projects\sandbox\trunk\test\..\.\file.txt
C:\projects\sandbox\trunk\file.txt

Vì vậy, getPath()cung cấp cho bạn đường dẫn dựa trên đối tượng Tệp, có thể có hoặc không tương đối; getAbsolutePath()cung cấp cho bạn một đường dẫn tuyệt đối đến tập tin; và getCanonicalPath()cung cấp cho bạn đường dẫn tuyệt đối duy nhất đến tệp. Lưu ý rằng có một số lượng lớn các đường dẫn tuyệt đối trỏ đến cùng một tệp, nhưng chỉ có một đường dẫn chính tắc.

Khi nào nên sử dụng mỗi? Phụ thuộc vào những gì bạn đang cố gắng thực hiện, nhưng nếu bạn đang cố gắng xem liệu hai người Filescó đang chỉ vào cùng một tệp trên đĩa hay không, bạn có thể so sánh các đường dẫn chính tắc của họ. Chỉ là một ví dụ.


7
Người ta cho rằng Java đã thực hiện sai đường dẫn "tuyệt đối"; nó thực sự nên loại bỏ bất kỳ thành phần đường dẫn tương đối nào trong một đường dẫn tuyệt đối. Các hình thức chính tắc sau đó sẽ loại bỏ bất kỳ liên kết hoặc mối nối FS nào trong đường dẫn.
Lawrence Dol

but if you were trying to see if two Files are pointing at the same file on diskLàm sao? làm ơn ví dụ?
Asif Mushtaq

@UnKnown: Bạn sẽ sử dụng đường dẫn chính tắc cho điều đó.
Lawrence Dol

67

Nói ngắn gọn:

  • getPath()nhận được chuỗi đường dẫn mà Fileđối tượng được xây dựng và nó có thể là thư mục hiện tại tương đối.
  • getAbsolutePath() nhận được chuỗi đường dẫn sau khi giải quyết nó theo thư mục hiện tại nếu nó tương đối, dẫn đến một đường dẫn đủ điều kiện.
  • getCanonicalPath()nhận được chuỗi đường dẫn sau khi giải quyết bất kỳ đường dẫn tương đối nào đối với thư mục hiện tại và xóa mọi đường dẫn tương đối ( ...) và bất kỳ hệ thống tệp nào liên kết để trả về một đường dẫn mà hệ thống tệp xem là phương tiện chính quy để tham chiếu đối tượng hệ thống tệp mà nó trỏ tới.

Ngoài ra, mỗi trong số này có một tệp tương đương trả về Fileđối tượng tương ứng .


36

getPath()trả về đường dẫn được sử dụng để tạo Fileđối tượng Giá trị trả về này không thay đổi dựa trên vị trí nó được chạy (kết quả bên dưới là cho các cửa sổ, dấu phân cách rõ ràng là khác ở nơi khác)

File f1 = new File("/some/path");
String path = f1.getPath(); // will return "\some\path"

File dir = new File("/basedir");
File f2 = new File(dir, "/some/path");
path = f2.getPath(); // will return "\basedir\some\path"

File f3 = new File("./some/path");
path = f3.getPath(); // will return ".\some\path"

getAbsolutePath()sẽ giải quyết đường dẫn dựa trên vị trí thực hiện hoặc ổ đĩa. Vì vậy, nếu chạy từ c:\test:

path = f1.getAbsolutePath(); // will return "c:\some\path"
path = f2.getAbsolutePath(); // will return "c:\basedir\some\path"
path = f3.getAbsolutePath(); // will return "c:\test\.\basedir\some\path"

getCanonicalPath()là phụ thuộc hệ thống. Nó sẽ giải quyết vị trí duy nhất mà đường dẫn đại diện. Vì vậy, nếu bạn có bất kỳ "." Trong đường dẫn, chúng thường sẽ bị xóa.

Khi nào nên sử dụng chúng. Nó phụ thuộc vào những gì bạn đang cố gắng để đạt được. getPath()là hữu ích cho tính di động.getAbsolutePath()rất hữu ích để tìm vị trí hệ thống tệp và getCanonicalPath()đặc biệt hữu ích để kiểm tra xem hai tệp có giống nhau không.


bạn có thể cho tôi bất kỳ ví dụ về điều này? getCanonicalPath() is particularly useful to check if two files are the same.
Asif Mushtaq

20

Điều quan trọng khiến bạn phải suy nghĩ là Filelớp học cố gắng thể hiện một quan điểm về cái mà Sun muốn gọi là "tên đường dẫn phân cấp" (về cơ bản là một đường dẫn như c:/foo.txthoặc /usr/muggins). Đây là lý do tại sao bạn tạo các tệp theo đường dẫn. Các hoạt động bạn đang mô tả là tất cả các hoạt động dựa trên "tên đường dẫn" này.

  • getPath()tìm nạp đường dẫn mà Tệp được tạo bằng ( ../foo.txt)
  • getAbsolutePath()tìm nạp đường dẫn mà Tệp đã được tạo, nhưng bao gồm thông tin về thư mục hiện tại nếu đường dẫn là tương đối ( /usr/bobstuff/../foo.txt)
  • getCanonicalPath() cố gắng tìm nạp một đại diện duy nhất của đường dẫn tuyệt đối đến tệp. Điều này giúp loại bỏ sự gián tiếp từ ".." và "." tài liệu tham khảo ( /usr/foo.txt).

Lưu ý tôi nói các nỗ lực - khi hình thành Đường dẫn Canonical, VM có thể ném IOException. Điều này thường xảy ra bởi vì nó đang thực hiện một số hoạt động của hệ thống tập tin, bất kỳ một trong số đó có thể thất bại.


3

Tôi thấy tôi hiếm khi có nhu cầu sử dụng getCanonicalPath(), nhưng, nếu được cung cấp một Tệp có tên tệp có định dạng DOS 8.3 trên Windows, chẳng hạn như java.io.tmpdirtrả về thuộc tính Hệ thống, thì phương thức này sẽ trả về tên tệp "đầy đủ".

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.