ความแตกต่างระหว่าง getPath (), getAbsolutePath () และ getCanonicalPath () ใน Java คืออะไร


583

อะไรคือความแตกต่างระหว่างgetPath(), getAbsolutePath()และgetCanonicalPath()ใน Java?

และเมื่อไหร่ที่ฉันจะใช้แต่ละอัน?


อย่าลืมPath.toAbsolutePath().normalize()ว่าเป็นพื้นที่ตรงกลางที่ดีระหว่างเส้นทางแบบบัญญัติ (จริง) และเส้นทางสัมบูรณ์
eckes

คำตอบ:


625

พิจารณาชื่อไฟล์เหล่านี้:

C:\temp\file.txt - นี่คือเส้นทางพา ธ สัมบูรณ์และเส้นทางบัญญัติ

.\file.txt- นี่คือเส้นทาง มันไม่ใช่เส้นทางแบบสัมบูรณ์หรือเส้นทางแบบบัญญัติ

C:\temp\myapp\bin\..\\..\file.txt- นี่คือเส้นทางและเส้นทางที่แน่นอน มันไม่ใช่เส้นทางแบบบัญญัติ

เส้นทางที่เป็นที่ยอมรับเป็นเส้นทางที่แน่นอนเสมอ

การแปลงจากพา ธ ไปยังพา ธ แบบบัญญัติทำให้มันสมบูรณ์ (โดยปกติจะอยู่ที่ไดเร็กทอรีการทำงานปัจจุบันเช่น./file.txtจะกลายเป็นc:/temp/file.txt) เส้นทางบัญญัติของไฟล์เพียง "ชำระ" เส้นทางการลบและการแก้ไขสิ่งที่ชอบ..\และการแก้ไข symlink (ในยูนิกซ์)

ให้สังเกตตัวอย่างต่อไปนี้ด้วย 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());

ในขณะที่เส้นทางทั้งสองอ้างถึงตำแหน่งเดียวกันผลลัพธ์จะแตกต่างกันมาก:

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

11
FWIW ไม่ใช่สิ่งที่ระบุว่าC:\temp\file.txtเป็นเส้นทางแบบบัญญัติ - ไดเรกทอรี temp อาจเป็นซอฟต์ลิงค์ระบบหรือฮาร์ดลิงก์ (junction ใน NTFS) และ file.txt อาจเป็นซอฟต์ลิงก์ ฉันไม่ทราบว่าระบบไฟล์สามารถแยกแยะฮาร์ดลิงก์ไปยังไฟล์ได้หรือไม่
Lawrence Dol

1
เส้นทางไม่ได้พิจารณาประเด็นเหล่านั้นหรือการมีอยู่ขององค์ประกอบใด ๆ จริงๆเพียงแค่ไวยากรณ์ของมัน
escape-llc

มันเป็นเส้นทางที่ยอมรับ (แตกต่างจากเส้นทางปกติ) จะตีระบบไฟล์
eckes

1
โดยทั่วไปฉันไม่สามารถเห็นเหตุผลว่าทำไมหนึ่งควรใช้แทนgetAbsolutePath() getCanonicalPath()มันดูดีขึ้นเพราะส่วนที่เป็นที่ยอมรับจะแก้ไข../ส่วนเหล่านั้นโดยอัตโนมัติ
Scadge

อย่าลืมว่าgetCanonicalPathการใช้เวลาIOExceptionสักพักgetAbsolutePathไม่ได้เกิดขึ้นหากนี่เป็นการพิจารณา
รถเข็นที่ถูกทอดทิ้ง

129

วิธีที่ดีที่สุดที่ฉันพบว่ารู้สึกถึงสิ่งต่าง ๆ เช่นนี้คือการลองใช้:

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

ผลลัพธ์ของคุณจะเป็นอย่างไร:

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

ดังนั้นgetPath()ให้เส้นทางตามวัตถุไฟล์ซึ่งอาจหรืออาจจะไม่สัมพันธ์; getAbsolutePath()ให้เส้นทางที่แน่นอนแก่คุณไปยังไฟล์ และgetCanonicalPath()ให้เส้นทางแบบสัมบูรณ์ที่ไม่ซ้ำใครกับไฟล์ โปรดสังเกตว่ามีเส้นทางสัมบูรณ์จำนวนมากที่ชี้ไปที่ไฟล์เดียวกัน แต่มีเพียงเส้นทางเดียวเท่านั้น

ใช้เมื่อใด? ขึ้นอยู่กับสิ่งที่คุณพยายามจะทำ แต่ถ้าคุณพยายามดูว่าFilesมีสองคนชี้ไปที่ไฟล์เดียวกันบนดิสก์หรือไม่คุณสามารถเปรียบเทียบเส้นทางที่เป็นที่ยอมรับได้ เพียงแค่ตัวอย่างเดียว


7
เป็นที่ถกเถียงกันอยู่ว่า Java ได้รับการใช้งานเส้นทางที่ "แน่นอน" ผิด; ควรลบองค์ประกอบของเส้นทางที่สัมพันธ์กันในเส้นทางที่สมบูรณ์ แบบฟอร์มมาตรฐานจะลบลิงก์หรือจุดเชื่อมต่อ FS ใด ๆ ในเส้นทาง
Lawrence Dol

but if you were trying to see if two Files are pointing at the same file on diskอย่างไร? ตัวอย่างไหม
Asif Mushtaq

@UnKnown: คุณต้องการใช้เส้นทางแบบบัญญัติสำหรับสิ่งนั้น
Lawrence Dol

67

ในระยะสั้น:

  • getPath()รับค่าสตริงพา ธ ที่Fileวัตถุถูกสร้างขึ้นด้วยและอาจเป็นไดเรกทอรีปัจจุบันที่สัมพันธ์กัน
  • getAbsolutePath() รับค่าสตริงพา ธ หลังจากแก้ไขกับไดเร็กทอรีปัจจุบันหากเป็นค่าที่สัมพันธ์กันทำให้เกิดพา ธ แบบเต็ม
  • getCanonicalPath()รับค่าสตริงพา ธ หลังจากแก้ไขพา ธ สัมพัทธ์กับไดเร็กทอรีปัจจุบันและลบพา ธ สัมพัทธ์ ( .และ..) และลิงก์ระบบไฟล์ใด ๆ เพื่อส่งคืนพา ธ ที่ระบบไฟล์พิจารณาว่าเป็นที่ยอมรับในการอ้างอิงวัตถุระบบไฟล์ที่ชี้ไป

นอกจากนี้แต่ละไฟล์ยังมีไฟล์เทียบเท่าซึ่งจะส่งคืนFileวัตถุที่เกี่ยวข้อง


36

getPath()ส่งคืนเส้นทางที่ใช้ในการสร้างFileวัตถุ ค่าส่งคืนนี้จะไม่เปลี่ยนแปลงตามสถานที่ตั้งที่เรียกใช้ (ผลลัพธ์ด้านล่างสำหรับ windows ตัวคั่นจะแตกต่างกันอย่างชัดเจนที่อื่น)

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()จะแก้ไขเส้นทางตามตำแหน่งการดำเนินการหรือไดรฟ์ ดังนั้นถ้าวิ่งจาก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()ขึ้นอยู่กับระบบ มันจะแก้ไขตำแหน่งที่ไม่ซ้ำเส้นทางที่แสดงถึง ดังนั้นหากคุณมี "." อยู่ในเส้นทางพวกเขาจะถูกลบโดยทั่วไป

ในฐานะที่เป็นเมื่อจะใช้พวกเขา ขึ้นอยู่กับสิ่งที่คุณพยายามทำ getPath()มีประโยชน์สำหรับการพกพา getAbsolutePath()มีประโยชน์ในการค้นหาตำแหน่งของระบบไฟล์และgetCanonicalPath()มีประโยชน์อย่างยิ่งในการตรวจสอบว่ามีสองไฟล์เหมือนกันหรือไม่


คุณสามารถยกตัวอย่างจากเรื่องนี้ได้ไหม getCanonicalPath() is particularly useful to check if two files are the same.
Asif Mushtaq

20

สิ่งสำคัญที่จะทำให้คุณนึกถึงคือFileชั้นเรียนพยายามแสดงมุมมองของสิ่งที่ Sun ต้องการเรียกว่า "ชื่อพา ธ แบบลำดับชั้น" (โดยทั่วไปเป็นเส้นทางแบบc:/foo.txtหรือ/usr/muggins) นี่คือเหตุผลที่คุณสร้างไฟล์ในแง่ของเส้นทาง การดำเนินการที่คุณกำลังอธิบายเป็นการดำเนินการทั้งหมดกับ "ชื่อพา ธ " นี้

  • getPath()เรียกเส้นทางที่ไฟล์ถูกสร้างขึ้นด้วย ( ../foo.txt)
  • getAbsolutePath()เรียกเส้นทางที่ไฟล์ถูกสร้างขึ้นมา แต่รวมถึงข้อมูลเกี่ยวกับไดเรกทอรีปัจจุบันหากเส้นทางสัมพันธ์กัน ( /usr/bobstuff/../foo.txt)
  • getCanonicalPath() พยายามดึงการแทนค่าที่ไม่ซ้ำกันของพา ธ สัมบูรณ์ไปยังไฟล์ สิ่งนี้จะช่วยลดการอ้อมจาก ".. " และ "." การอ้างอิง ( /usr/foo.txt)

หมายเหตุผมพูดความพยายาม - ในการสร้างเส้นทาง Canonical ที่ VM IOExceptionสามารถโยน สิ่งนี้มักจะเกิดขึ้นเพราะมันกำลังทำการดำเนินการบางอย่างของระบบไฟล์ใด ๆ ที่อาจล้มเหลว


3

ฉันพบว่าฉันไม่จำเป็นต้องใช้getCanonicalPath()แต่ถ้าให้ไฟล์ที่มีชื่อไฟล์ที่อยู่ในรูปแบบ DOS 8.3 บน Windows เช่นjava.io.tmpdirคุณสมบัติ System return แล้ววิธีนี้จะส่งคืนชื่อไฟล์ "เต็ม"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.