ความแตกต่างระหว่าง File.separator และเครื่องหมายทับในพา ธ


200

ความแตกต่างระหว่างการใช้File.separatorและปกติ/ใน Java Path-String คืออะไร?

ตรงกันข้ามกับ\\ความเป็นอิสระของแพลตฟอร์มแบ็กสแลชสองครั้งดูเหมือนจะไม่ใช่เหตุผลเนื่องจากทั้งสองรุ่นทำงานภายใต้ Windows และ Unix

public class SlashTest {
    @Test
    public void slash() throws Exception {
        File file = new File("src/trials/SlashTest.java");
        assertThat(file.exists(), is(true));
    }

    @Test
    public void separator() throws Exception {
        File file = new File("src" + File.separator + "trials" + File.separator + "SlashTest.java");
        assertThat(file.exists(), is(true));
    }
}

การใช้ถ้อยคำคำถามถ้า/งานบน Unix และ Windows จึงควรหนึ่งเคยต้องการที่จะใช้งานFile.separator?


5
@Ring 'เหตุผลทางประวัติศาสตร์' เช่นอะไร
มาร์ควิสแห่ง Lorne

คำตอบ:


246

ด้วยไลบรารี Java สำหรับจัดการกับไฟล์คุณสามารถใช้/(สแลช, ไม่ใช่แบ็กสแลช) ในทุกแพลตฟอร์มได้อย่างปลอดภัย รหัสห้องสมุดจัดการสิ่งที่แปลเป็นเส้นทางเฉพาะแพลตฟอร์มภายใน

อย่างไรก็ตามคุณอาจต้องการใช้File.separatorใน UI เนื่องจากเป็นการดีที่สุดที่จะแสดงให้คนอื่นเห็นว่าอะไรจะทำให้รู้สึกในระบบปฏิบัติการของพวกเขาแทนที่จะเป็นสิ่งที่สมเหตุสมผลกับ Java

อัปเดต : ฉันไม่สามารถค้นหาการทำงานของ "คุณสามารถใช้เครื่องหมายทับ" ได้ในเวลาห้านาที ตอนนี้ฉันแน่ใจว่าฉันเห็นมันเป็นเอกสาร แต่ในกรณีที่ไม่มีการอ้างอิงอย่างเป็นทางการ (เพราะความจำของฉันไม่สมบูรณ์) ฉันจะใช้งานFile.separatorเพราะคุณรู้ว่ามันจะได้ผล


2
นี่อาจเป็นปัญหากับประสิทธิภาพการทำงานเนื่องจากคุณคาดหวังว่าตัวคั่นจะถูกแปลงเป็นอย่างอื่นในขณะทำงาน นอกจากนี้อย่าคาดหวังว่าสิ่งนี้จะเกิดขึ้นใน JVM ที่ไม่สนับสนุนทั้งหมด
jpabluz

7
@TJ Crowder: "ฉันไม่สามารถค้นหาภายในห้านาทีเพื่อค้นหา 'คุณสามารถใช้เครื่องหมายทับ' พฤติกรรมที่บันทึกไว้ได้" ไม่ใช่คุณสมบัติของ JVM เป็นคุณลักษณะของ Windows NT API
Powerlord

12
@ Powerlord: ถ้า Windows ทำเช่นนั้นก็ยอดเยี่ยม - แต่ห้องสมุด (ไม่ใช่ JVM) ก็ทำได้ดีเช่นกัน โดยเฉพาะFileใช้FileSystem.normalizeทั่วสถานที่เพื่อ "ปกติ" เส้นทางที่ได้รับผ่าน API สาธารณะและเกือบทุกอย่างที่เกี่ยวข้องกับสตริงพา ธ ไฟล์ (ตัวอย่างเช่นFileWriter(String)) ใช้Fileภายใต้หน้าปก
TJ Crowder

9
ตั้งแต่ Java7 ไม่จำเป็นต้องใช้ File.separator อีกต่อไป มันง่ายและสะอาดกว่ามากในการใช้ java.nio.file.Paths (Paths.get (ก่อนอื่น ... )) สำหรับ dir to dir และ dir to filename ที่เข้าร่วม
magiccrafter

6
@jpabluz 'ปัญหาเกี่ยวกับประสิทธิภาพ'! คุณจริงจังไหม เมื่อพิจารณาถึงชื่อไฟล์ที่ใช้งานจะถูกใส่ลงบนดิสก์ผลกระทบรันไทม์ของการแปลนั้นไม่มีความสำคัญมาก มันควรจะได้รับการสนับสนุนโดย JVM ใด ๆ Fileตามที่มันเป็นส่วนหนึ่งของข้อกำหนดของ
มาร์ควิสแห่ง Lorne

316

คุณใช้File.separatorเพราะสักวันโปรแกรมของคุณอาจทำงานบนแพลตฟอร์มที่พัฒนาในพื้นที่ห่างไกลดินแดนแห่งสิ่งแปลกประหลาดและคนแปลกหน้าที่ม้าร้องไห้และวัวใช้งานลิฟต์ทั้งหมด ในดินแดนแห่งนี้ผู้คนใช้อักษร ":" เป็นตัวคั่นไฟล์ตามธรรมเนียมแล้ว JVM จะทำตามความปรารถนาของพวกเขา


4
Yup, Pointy เอาพวกเราไปที่ Elbonia (หวังว่าเขาจะไม่มีทรงผมที่แหลม ;-) (เล่นปุ๊กข้างใน)
Riduidel

4
"... และวัวใช้งานลิฟต์ทั้งหมด" เช่นกันฉันไม่ได้จิบกาแฟเมื่ออ่าน สุกใส
TJ Crowder

8
ในประเทศดังกล่าวคุณจะใช้ประโยชน์จาก org.apache.chicken.elevators.OevatorUtility class ใหม่ซึ่งใช้ความบ้าคลั่งทั้งหมดนี้เพื่อความสะดวกของคุณ
สมอง

27

แม้ว่าการใช้ File.separator เพื่ออ้างอิงชื่อไฟล์นั้นเกินขีด จำกัด (สำหรับผู้ที่จินตนาการถึงดินแดนอันไกลโพ้นฉันคิดว่าการใช้ JVM ของพวกเขาจะแทนที่/ด้วยด้วย:เช่นเดียวกับ windows jvm แทนที่ด้วย a \)

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


11

ตกลงลองตรวจสอบโค้ด
File.javaบรรทัด 428 ถึง 435 ในFile.<init>:

String p = uri.getPath();
if (p.equals(""))
    throw new IllegalArgumentException("URI path component is empty");

// Okay, now initialize
p = fs.fromURIPath(p);
if (File.separatorChar != '/')
p = p.replace('/', File.separatorChar);

และอ่านfs/*(FileSystem)*/.fromURIPath()เอกสาร:

java.io.FileSystem
พับลิกบทคัดย่อ String จากURIPath (เส้นทางพา ธ )
โพสต์กระบวนการสตริง URI ที่กำหนดหากจำเป็น สิ่งนี้ใช้กับ win32 เช่นการแปลง "/ c: / foo" เป็น "c: / foo" สตริงพา ธ ยังคงมีตัวคั่นสแลช รหัสในระดับไฟล์จะแปลพวกเขาหลังจากที่วิธีนี้กลับมา

ซึ่งหมายความว่าFileSystem.fromURIPath()โพสต์การประมวลผลบนเส้นทาง URI เฉพาะใน Windows และเพราะในบรรทัดถัดไป

p = p.replace('/', File.separatorChar);

มันแทนที่แต่ละ '/' ขึ้นอยู่กับระบบseperatorCharคุณสามารถมั่นใจได้ว่า '/' ปลอดภัยในทุกระบบปฏิบัติการ


8

มีระบบปฏิบัติการมากกว่า Unix และ Windows (อุปกรณ์พกพา ฯลฯ ) และ Java เป็นที่รู้จักสำหรับการพกพา แนวทางปฏิบัติที่ดีที่สุดคือการใช้เพื่อให้ JVM สามารถกำหนดได้ว่าระบบใดที่ดีที่สุดสำหรับระบบปฏิบัติการนั้น


ระบบปฏิบัติการเหล่านั้นส่วนใหญ่รันยูนิกซ์บางตัว :ตัวคั่นลักษณะ Mac เก่าได้หายไปนาน ดูเหมือนว่าทุกคน แต่ Windows จะใช้มาตรฐาน/อีกต่อไป และแม้แต่หน้าต่างก็ดูเหมือนว่าจะจัดการกับการทับได้ดี ลองcd /windows/systemระบบ Windows 10 จากไดรฟ์ระบบหลักของคุณ ในขณะที่คุณยังต้องการแสดงพา ธ โดยใช้ตัวแยกระบบ (เพื่อไม่ให้ผู้ใช้สับสน) คุณสามารถใช้ฟอร์เวิร์ดสแลชได้/ทุกที่และมั่นใจได้ว่าโค้ดของคุณจะทำงานได้ทุกที่ที่คุณมีโอกาสปรับใช้
Shadow Man

7

แม้ว่ามันจะไม่ได้สร้างความแตกต่างมากนักในทางกลับกัน

แน่ใจว่าคุณสามารถใช้ '/' หรือ '\' ในไฟล์ใหม่ (เส้นทางของสตริง) แต่ File.getPath () จะให้หนึ่งในนั้นเท่านั้น


การแก้ไขเล็กน้อย ... ในWindowsคุณสามารถใช้สแลชไปข้างหน้า/หรือข้างหลัง \\ แต่ที่อื่นคุณควรใช้ฟอร์เวิร์ดสแลช/หรือคุณจะมีปัญหา
Shadow Man

6

ไปงานเลี้ยงสาย ฉันใช้ Windows 10 พร้อม JDK 1.8 และ Eclipse MARS 1
ฉันพบสิ่งนั้น

getClass().getClassLoader().getResourceAsStream("path/to/resource");

ทำงานและ

getClass().getClassLoader().getResourceAsStream("path"+File.separator+"to"+File.separator+"resource");

ไม่ทำงานและ

getClass().getClassLoader().getResourceAsStream("path\to\resource");

ไม่ทำงาน, ไม่เป็นผล. สองอันสุดท้ายเทียบเท่ากัน ดังนั้น ... ฉันมีเหตุผลที่ดีที่จะไม่ใช้ File.separator


6
ในบรรทัดนี้getClass().getClassLoader().getResourceAsStream("path\to\resource");มีการจัดระเบียบ ( \t) และการคืนสินค้า ( \r)
เตฟาน

9
นั่นเป็นสถานการณ์ที่แตกต่างสำหรับคำถาม เมธอด getResourceAsStream ของ ClassLoader ไม่ได้ใช้พา ธ ไฟล์ แต่ชื่อทรัพยากรที่อาจหรืออาจไม่ได้อยู่ในระบบไฟล์และมีการบันทึกไว้ว่ายอมรับ '/' เป็นตัวคั่นพา ธ ของทรัพยากรเท่านั้น
daiscog

@ สเตฟานไม่มีการหลบหนีที่ตลกเนื่องจากFile.separatorเป็นแบ็กสแลช มีเฉพาะในสตริงที่มีการกำหนดโค้ดแบบแข็งซึ่งจะถือว่าเป็นอักขระเลี่ยงที่คุณต้องหลบหลีกแบ็กสแลช หากคุณเก็บอักขระไว้ในไฟล์ข้อความหรือในcharหรือStringจากนั้นคุณไม่จำเป็นต้องหลบเลี่ยงเป็นครั้งที่ 2 เนื่องจากอักขระนั้นถูกแปลงเป็นอักขระแบ็กสแลชที่คาดไว้ ลองใช้วิธีนี้ดูด้วยตัวคุณเอง:String backslash = "\\"; System.out.println("welcome" + backslash + "to" + backslash + "reality");
Shadow Man

2
@ สเตฟานโอ้เข้าใจแล้วคุณกำลังพูดถึงบรรทัดที่ 3 คุณถูก. ในบรรทัดนั้น (สตริงที่เข้ารหัสยาก) คุณจะต้องหลีกเลี่ยงอักขระเลี่ยง ดวงตาของฉันหยุดที่บรรทัดที่ 2 และฉันไม่ได้สังเกตเห็นบรรทัดที่ 3 ในตอนแรก
Shadow Man

3

พกพาธรรมดาและเรียบง่าย


ใช่สำหรับพกพาไม่ได้ใช้เครื่องหมายทับขวา ใช้ทับหรือคั่นระบบ/ File.separatorทั้งคู่ดูเหมือนจะทำงานได้ทุกที่ ในขณะที่File.separatorรับประกันว่าจะทำงานได้ทุกที่เฉือนอย่างง่าย/ก็ดูเหมือนว่าจะทำงานได้ทุกที่ ถ้ามันไม่ทำงานที่ไหนสักแห่งฉันก็อยากจะฟัง ฉันเชื่อว่ามันใช้ได้กับทุกระบบ อย่างน้อยที่สุดฉันยังไม่พบที่ใดที่/ไม่ทำงาน (Mac OSX, Windows, * nix, Android, iOS - ฉันยังไม่ได้ตรวจสอบ Mac OSX ก่อนที่ใช้ ":" เป็นตัวคั่น OS / 2, NeXT หรือระบบปฏิบัติการโบราณอื่น ๆ )
Shadow Man

1

"Java SE8 สำหรับโปรแกรมเมอร์" อ้างว่าJavaจะจัดการกับทั้ง (pp. 480 วรรคสุดท้าย) ตัวอย่างอ้างว่า:

c:\Program Files\Java\jdk1.6.0_11\demo/jfc

จะแยกวิเคราะห์ได้ดี จดเครื่องหมายคั่น (Unix-style) ตัวสุดท้าย

มันไม่มีรสนิยมที่ดีและอาจผิดพลาดได้ง่าย แต่มันก็เป็นสิ่งที่พวกเขาเรียกร้อง (Deitel และ Deitel)

ฉันคิดว่าความสับสนสำหรับผู้คนมากกว่า Java เป็นเหตุผลเพียงพอที่จะไม่ใช้คุณสมบัตินี้ (ผิดพลาด?)


1

ในฐานะที่เป็นสุภาพบุรุษอธิบายความแตกต่างกับรายละเอียดที่แตกต่าง

ฉันอยากจะแนะนำการใช้Apache Commons io api คลาสFilenameUtilsเมื่อจัดการกับไฟล์ในโปรแกรมที่มีความเป็นไปได้ในการปรับใช้กับระบบปฏิบัติการหลายระบบ


0

ชื่อพา ธ สำหรับไฟล์หรือไดเรกทอรีถูกระบุโดยใช้แบบแผนการตั้งชื่อของระบบโฮสต์ อย่างไรก็ตามคลาส File กำหนดค่าคงที่ขึ้นอยู่กับแพลตฟอร์มที่สามารถใช้ในการจัดการชื่อไฟล์และไดเรกทอรีในทางที่ไม่ขึ้นกับแพลตฟอร์ม

Files.seperator กำหนดอักขระหรือสตริงที่แยกไดเรกทอรีและส่วนประกอบของไฟล์ในชื่อพา ธ ตัวแยกนี้คือ '/', '\' หรือ ':' สำหรับ Unix, Windows และ Macintosh ตามลำดับ


":" สำหรับ Macintosh นั้นเก่าแก่ ตั้งแต่ OSX, Mac ก็ใช้ "/" (สแลชฟอร์เวิร์ด) เนื่องจากมันใช้รูปแบบของ UNIX พร้อมกับระบบไฟล์ UNIX มาตรฐานภายใต้ประทุน
Shadow Man


0

การใช้ File.separator ทำให้ Ubuntu สร้างไฟล์ที่มีชื่อ "\" แทนชื่อของไดเรกทอรี บางทีฉันอาจขี้เกียจกับวิธีที่ฉันสร้างไฟล์ (และไดเรกทอรี) และสามารถหลีกเลี่ยงได้โดยไม่คำนึงถึงใช้ "/" ทุกครั้งเพื่อหลีกเลี่ยงไฟล์ที่มี "\" อยู่ในชื่อ


0

หากคุณพยายามสร้างไฟล์จากพา ธ ที่พร้อมใช้งาน (บันทึกในฐานข้อมูลตัวอย่าง) โดยใช้ตัวคั่น Linux ฉันควรทำอย่างไร

อาจจะแค่ใช้พา ธ เพื่อสร้างไฟล์:

new File("/shared/folder/file.jpg");

แต่ Windows ใช้ตัวคั่นอื่น ( \) ดังนั้นทางเลือกแปลงตัวแบ่งเครื่องหมายทับเป็นแพลตฟอร์มอิสระหรือไม่ ชอบ:

new File(convertPathToPlatformIndependent("/shared/folder"));

วิธีนี้convertPathToPlatformIndependentอาจจะมีการแบ่งบางอย่างโดย "/" และเข้าร่วมกับ File.separator

สำหรับฉันมันไม่ดีสำหรับภาษาที่เป็นอิสระจากแพลตฟอร์ม (ใช่มั้ย) และ Java รองรับการใช้งาน/บน Windows หรือ Linux อยู่แล้ว แต่ถ้าคุณทำงานกับเส้นทางและต้องจำไว้ว่าต้องมีการเปลี่ยนแปลงครั้งนี้ทุกครั้งจะเป็นฝันร้ายและคุณจะไม่ได้รับประโยชน์อย่างแท้จริงสำหรับแอปพลิเคชั่นในอนาคต (อาจเป็นในจักรวาลที่ @Pointy อธิบาย)

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