Sự khác biệt giữa File.separator và dấu gạch chéo trong đường dẫn


200

Sự khác biệt giữa việc sử dụng File.separatorvà bình thường /trong Chuỗi đường dẫn Java là gì?

Ngược lại, \\độc lập nền tảng dấu gạch chéo kép dường như không phải là lý do, vì cả hai phiên bản đều hoạt động trong Windows và 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));
    }
}

Để viết lại câu hỏi, nếu /hoạt động trên Unix và Windows, tại sao người ta phải muốn sử dụng File.separator?


5
@Ring 'Lý do lịch sử' như là gì?
Hầu tước Lorne

Câu trả lời:


246

Với các thư viện Java để xử lý các tệp, bạn có thể sử dụng một cách an toàn /(gạch chéo, không gạch chéo ngược) trên tất cả các nền tảng. Mã thư viện xử lý việc dịch mọi thứ thành các đường dẫn cụ thể trong nền tảng.

File.separatorTuy nhiên, bạn có thể muốn sử dụng trong UI, vì tốt nhất là cho mọi người thấy những gì sẽ có ý nghĩa trong HĐH của họ, hơn là những gì có ý nghĩa với Java.

Cập nhật : Tôi đã không thể, trong năm phút tìm kiếm, để tìm thấy hành vi "bạn luôn có thể sử dụng dấu gạch chéo" được ghi lại. Bây giờ, tôi chắc chắn tôi đã thấy nó được ghi lại, nhưng trong sự vắng mặt của việc tìm một tài liệu tham khảo chính thức (vì bộ nhớ của tôi không hoàn hảo), tôi sẽ sử dụng File.separatorvì bạn biết rằng nó sẽ hoạt động.


2
Đây cũng có thể là một vấn đề với hiệu suất, vì bạn đang mong đợi dấu phân cách sẽ được chuyển đổi thành một cái gì đó khác trong thời gian chạy. Ngoài ra, đừng hy vọng điều này xảy ra trong tất cả các JVM không được hỗ trợ ngoài kia.
jpabluz

7
@TJ Crowder: "Tôi đã không thể, trong năm phút tìm kiếm, để tìm thấy 'bạn luôn có thể sử dụng một dấu gạch chéo' được ghi lại." Đây không phải là một tính năng của JVM, đây là một tính năng của Windows NT API.
Powerlord

12
@Powerlord: Nếu Windows cũng làm điều đó, thật tuyệt - nhưng thư viện (không phải JVM) cũng làm điều đó. Cụ thể, Filesử dụng FileSystem.normalizemọi nơi để "bình thường hóa" các đường dẫn nhận được thông qua API công khai và gần như mọi thứ liên quan đến chuỗi đường dẫn tệp (ví dụ FileWriter(String):) sử dụng Filetrong các trang bìa.
TJ Crowder

9
Vì Java7 không cần sử dụng File.separator nữa. Nó đơn giản và gọn gàng hơn nhiều khi sử dụng java.nio.file.Paths (Paths.get (đầu tiên, nhiều hơn ...)) cho dir để dir và dir để nối tên tệp.
Magiccrafter

6
@jpabluz 'Một vấn đề với hiệu suất'! Bạn nghiêm túc chứ? Xem xét việc sử dụng tên tệp được đưa vào đĩa, tác động thời gian chạy của bản dịch là không đáng kể. Nó nên được hỗ trợ bởi bất kỳ JVM nào, vì nó là một phần của đặc tả File.
Hầu tước Lorne

316

Bạn sử dụng File.separatorbởi vì một ngày nào đó chương trình của bạn có thể chạy trên một nền tảng được phát triển ở một vùng đất xa xôi, một vùng đất của những điều kỳ lạ và những người xa lạ, nơi ngựa khóc và bò vận hành tất cả các thang máy. Ở vùng đất này, mọi người thường sử dụng ký tự ":" làm dấu phân tách tệp và thật đáng sợ, JVM tuân theo mong muốn của họ.


4
Yup, Pointy thực sự đưa chúng ta đến elbonia (hy vọng anh ta không có mái tóc nhọn hoắt ;-) (chơi chữ bên trong)
Riduidel

4
"... và bò vận hành tất cả các thang máy." Cũng như tôi đã không uống một ngụm cà phê khi tôi đọc nó. Xuất sắc.
TJ Crowder

8
Ở một đất nước như vậy, bạn sẽ sử dụng lớp org.apache.chicken.elevators.OperatorUtility mới, trong đó nhúng tất cả sự điên rồ này để thuận tiện cho bạn.
Não

27

Mặc dù việc sử dụng File.separator để tham chiếu một tên tệp là quá mức cần thiết (đối với những người tưởng tượng ở xa đất liền, tôi tưởng tượng việc triển khai JVM của họ sẽ thay thế /bằng một :giống như windows jvm thay thế nó bằng a \).

Tuy nhiên, đôi khi bạn nhận được tham chiếu tệp, không tạo tệp và bạn cần phân tích cú pháp, và để có thể làm điều đó, bạn cần biết dấu phân cách trên nền tảng. File.separator giúp bạn làm điều đó.


11

OK hãy kiểm tra một số mã.
File.javadòng từ 428 đến 435 trong 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);

Và hãy đọc fs/*(FileSystem)*/.fromURIPath()tài liệu:


Chuỗi trừu tượng công khai java.io.FileSystem fromURIPath (Đường dẫn chuỗi) Xử lý sau chuỗi đường dẫn
URI đã cho nếu cần. Điều này được sử dụng trên win32, ví dụ, để chuyển đổi "/ c: / foo" thành "c: / foo". Chuỗi đường dẫn vẫn có dấu phân cách dấu gạch chéo; mã trong lớp File sẽ dịch chúng sau khi phương thức này trả về.

Điều này có nghĩa là FileSystem.fromURIPath()không xử lý bài đăng trên đường dẫn URI chỉ trong Windows và bởi vì trong dòng tiếp theo:

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

Nó thay thế từng '/' với hệ thống phụ thuộc seperatorChar, bạn luôn có thể chắc chắn rằng '/' an toàn trong mọi HĐH.


8

Chà, có nhiều HĐH hơn Unix và Windows (Thiết bị di động, v.v.) và Java được biết đến với tính di động. Cách thực hành tốt nhất là sử dụng nó, vì vậy JVM có thể xác định cái nào là tốt nhất cho HĐH đó.


Hầu hết các hệ điều hành này đều chạy một số biến thể của UNIX. Các :dải phân cách kiểu Mac cũ đã biến mất từ ​​lâu. Có vẻ như tất cả mọi người trừ Windows sử dụng tiêu chuẩn /nữa. Và thậm chí các cửa sổ dường như xử lý tốt dấu gạch chéo bây giờ. Hãy thử cd /windows/systemtrên hệ thống Windows 10 từ ổ đĩa hệ thống chính của bạn. Mặc dù bạn vẫn muốn hiển thị các đường dẫn bằng trình phân tách hệ thống (để không gây nhầm lẫn cho người dùng của mình), bạn chỉ có thể sử dụng dấu gạch chéo /ở mọi nơi khác và tự tin rằng mã của bạn sẽ hoạt động ở bất cứ đâu mà bạn có khả năng triển khai nó.
Shadow Man

7

Mặc dù nó không tạo ra nhiều khác biệt trên đường vào, nhưng nó lại đi trên đường về.

Chắc chắn bạn có thể sử dụng '/' hoặc '\' trong Tệp mới (đường dẫn chuỗi), nhưng File.getPath () sẽ chỉ cung cấp cho bạn một trong số chúng.


Chỉnh sửa nhẹ ... Trong Windows, bạn có thể sử dụng dấu gạch chéo tiến /hoặc lùi \\ . Nhưng bất cứ nơi nào khác, tốt hơn là bạn nên sử dụng dấu gạch chéo về phía trước /hoặc bạn sẽ gặp vấn đề.
Shadow Man

6

Đi dự tiệc muộn. Tôi đang dùng Windows 10 với JDK 1.8 và MARS Eclipse 1.
Tôi thấy rằng

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

công trình và

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

không hoạt động và

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

không hoạt động. Hai cái cuối cùng là tương đương. Vì vậy, ... tôi có lý do chính đáng để KHÔNG sử dụng File.separator.


6
Trong dòng này getClass().getClassLoader().getResourceAsStream("path\to\resource");, có một bảng ( \t) và trả về vận chuyển ( \r).
Stephan

9
Đó là một kịch bản khác nhau cho câu hỏi. Phương thức getResourceAsStream của ClassLoader không lấy đường dẫn Tệp, nhưng tên tài nguyên có thể có hoặc không có trên hệ thống tệp và được ghi nhận là chỉ chấp nhận '/' làm dấu tách đường dẫn tài nguyên.
daiscog

@Stephan không có chuyện vui thoát ra ở đó, vì File.separatorlà một dấu gạch chéo ngược. Nó chỉ có trong các chuỗi được mã hóa cứng, nơi nó được coi là một ký tự thoát mà bạn cần thoát khỏi dấu gạch chéo ngược. Nếu bạn đã lưu trữ ký tự trong một tệp văn bản hoặc trong một charhoặc Stringsau đó bạn không cần phải thoát nó lần thứ hai vì nó đã được chuyển đổi thành ký tự dấu gạch chéo dự kiến. Hãy thử điều này để tự mình xem:String backslash = "\\"; System.out.println("welcome" + backslash + "to" + backslash + "reality");
Shadow Man

2
@Stephan oh, tôi hiểu rồi ... Bạn đang nói về dòng thứ 3. Bạn nói đúng. Trong dòng đó (một chuỗi mã hóa cứng), bạn sẽ cần phải thoát ký tự thoát. Mắt tôi dừng lại ở dòng thứ 2 và tôi thậm chí không nhận thấy dòng thứ 3 lúc đầu.
Shadow Man

3

tính di động đơn giản và đơn giản.


Có, đối với tính di động, không sử dụng dấu gạch chéo ngược. Sử dụng dấu gạch chéo về phía trước /hoặc dấu phân cách hệ thống File.separator. Cả hai dường như làm việc ở khắp mọi nơi. Trong khi File.separatorđược đảm bảo để làm việc ở mọi nơi, thì dấu gạch chéo đơn giản /cũng có vẻ hoạt động ở mọi nơi. Nếu nó không hoạt động ở đâu đó, thì tôi rất muốn nghe về nó. Tôi tin rằng nó sẽ hoạt động trên tất cả các hệ thống. Ít nhất, tôi vẫn chưa tìm thấy bất cứ nơi nào /không hoạt động (Mac OSX, Windows, * nix, Android, iOS - Tôi chưa kiểm tra các máy Mac OSX trước đó sử dụng ":" như một dấu phân cách, OS / 2, NeXT hoặc bất kỳ hệ điều hành thực sự cổ xưa nào khác).
Shadow Man

1

"Java SE8 dành cho lập trình viên" tuyên bố rằng Java sẽ đối phó với một trong hai. (trang 480, đoạn cuối). Ví dụ tuyên bố rằng:

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

sẽ phân tích tốt Lưu ý đến dấu phân cách (kiểu Unix) cuối cùng.

Điều đó thật khó khăn và có thể dễ bị lỗi, nhưng đó là những gì họ (Delist và Delist) yêu cầu.

Tôi nghĩ rằng sự nhầm lẫn cho mọi người, thay vì Java, là lý do đủ để không sử dụng tính năng (mis?) Này.


1

Như các quý ông mô tả sự khác biệt với các chi tiết biến thể.

Tôi muốn giới thiệu việc sử dụng Apache Commons io api FilenameUtilskhi xử lý các tệp trong một chương trình với khả năng triển khai trên nhiều HĐH.


0

Tên đường dẫn cho một tệp hoặc thư mục được chỉ định bằng cách sử dụng các quy ước đặt tên của hệ thống máy chủ. Tuy nhiên, lớp Tệp định nghĩa các hằng số phụ thuộc nền tảng có thể được sử dụng để xử lý tên tệp và thư mục theo cách độc lập với nền tảng.

Files.seperator định nghĩa ký tự hoặc chuỗi phân tách thư mục và các thành phần tệp trong một tên đường dẫn. Dấu phân cách này lần lượt là '/', '\' hoặc ':' cho Unix, Windows và Macintosh.


":" Cho Macintosh là cổ xưa. Kể từ OSX, Mac cũng sử dụng "/" (dấu gạch chéo thuận) vì nó đang chạy một dạng UNIX với hệ thống tệp UNIX tiêu chuẩn dưới mui xe.
Shadow Man


0

Việc sử dụng File.separator đã khiến Ubuntu tạo các tệp có "\" trên tên của nó thay vì các thư mục. Có lẽ tôi đang lười biếng với cách tôi tạo tệp (và thư mục) và có thể tránh nó, bất kể, sử dụng "/" mỗi lần để tránh các tệp có "\" trên tên của nó


0

Nếu bạn đang cố gắng tạo một tệp từ một số đường dẫn sẵn sàng (được lưu trong cơ sở dữ liệu, ví dụ) bằng trình phân tách Linux, tôi nên làm gì?

Có lẽ chỉ cần sử dụng đường dẫn để tạo tập tin:

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

Nhưng Windows sử dụng một dấu phân cách khác ( \). Vì vậy, là sự thay thế chuyển đổi dấu phân cách dấu gạch chéo thành nền tảng độc lập? Giống:

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

Phương thức này convertPathToPlatformIndependentcó thể sẽ có một số loại được chia bởi "/" và tham gia với File.separator.

Đối với tôi, điều đó không tốt cho một ngôn ngữ độc lập với nền tảng (phải không?) Và Java đã hỗ trợ việc sử dụng /trên Windows hoặc Linux. Nhưng nếu bạn đang làm việc với các đường dẫn và cần nhớ chuyển đổi này mỗi lần thì đây sẽ là một cơn ác mộng và bạn sẽ không có bất kỳ lợi ích thực sự nào cho ứng dụng trong tương lai (có thể trong vũ trụ mà @Pointy mô tả).

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.