Różnica między File.separator a ukośnikiem w ścieżkach


200

Jaka jest różnica między używaniem File.separatora wartością normalną /w ciągu Java Path-String?

W przeciwieństwie do podwójnego odwrotnego ukośnika \\niezależność platformy nie wydaje się być powodem, ponieważ obie wersje działają pod Windows i 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));
    }
}

Aby przeformułować pytanie, jeśli /działa na systemach Unix i Windows, dlaczego warto chcieć używać File.separator?


5
@Ring „Powody historyczne”, takie jak co?
Markiz Lorne

Odpowiedzi:


245

Dzięki bibliotekom Java do obsługi plików możesz bezpiecznie używać /(slash, a nie backslash) na wszystkich platformach. Kod biblioteki wewnętrznie przetwarza tłumaczenia na ścieżki specyficzne dla platformy.

Możesz jednak chcieć używać File.separatorinterfejsu użytkownika, ponieważ najlepiej jest pokazać ludziom, co będzie miało sens w ich systemie operacyjnym, niż co ma sens w Javie.

Aktualizacja : w ciągu pięciu minut wyszukiwania nie byłem w stanie znaleźć udokumentowanego zachowania „zawsze możesz użyć ukośnika”. Teraz jestem pewien, że widziałem to udokumentowane, ale wbrew brakowi znalezienia oficjalnej referencji (ponieważ moja pamięć nie jest idealna), pozostanę przy użyciu, File.separatorponieważ wiesz, że to zadziała.


2
Może to również stanowić problem z wydajnością, ponieważ oczekuje się, że separator zostanie przekształcony w coś innego w czasie wykonywania. Nie należy także oczekiwać, że tak się stanie we wszystkich nieobsługiwanych maszynach JVM.
jpabluz,

7
@TJ Crowder: „Po pięciu minutach poszukiwań nie byłem w stanie znaleźć udokumentowanego zachowania„ zawsze możesz użyć ukośnika ”.” To nie jest funkcja JVM, to funkcja Windows NT API.
Władca

12
@Powerlord: Jeśli Windows to robi, świetnie - ale biblioteka (nie JVM) również to robi. W szczególności Fileużywa FileSystem.normalizewszędzie w celu „normalizacji” ścieżek otrzymywanych za pośrednictwem publicznego interfejsu API i prawie wszystko, co dotyczy ciągów ścieżek plików (na przykład FileWriter(String)), używa Filepod przykryciem.
TJ Crowder

9
Ponieważ Java7 nie wymaga już używania File.separator. O wiele łatwiejsze i prostsze jest używanie java.nio.file.Paths (Paths.get (najpierw, więcej ...)) do łączenia katalogów z katalogami i łączenia plików z katalogami.
magiccrafter

6
@jpabluz „Problem z wydajnością”! Mówisz poważnie? Biorąc pod uwagę zastosowania nazw plików na dysku, wpływ tłumaczenia na środowisko wykonawcze jest zupełnie nieistotny. Powinien być obsługiwany przez dowolną maszynę JVM, ponieważ jest to część specyfikacji File.
Markiz Lorne

316

Używasz, File.separatorponieważ pewnego dnia twój program może działać na platformie opracowanej w odległej krainie, krainie dziwnych rzeczy i obcych ludzi, gdzie konie płaczą, a krowy obsługują wszystkie windy. Na tej ziemi ludzie tradycyjnie używali znaku „:” jako separatora plików, a zatem JVM posłusznie spełnia ich życzenia.


4
Tak, Pointy naprawdę truje nas w Elbonii (mam nadzieję, że nie ma spiczastej fryzury ;-) (geek kalambur w środku)
Riduidel

4
„... a krowy obsługują wszystkie windy”. Równie dobrze nie wypiłem łyka kawy, kiedy to przeczytałem. Znakomity.
TJ Crowder

8
W takim kraju skorzystałbyś z nowej klasy org.apache.chicken.elevators.OperatorUtility, która osadza całe to szaleństwo dla twojej wygody.
Brain

27

Chociaż używanie File.separator do odwoływania się do nazwy pliku jest przesadą (dla tych, którzy wyobrażają sobie odległe ziemie, wyobrażam sobie, że ich implementacja JVM zastąpiłaby /:tak, jak jvm systemu Windows zamienia ją na a \).

Czasami jednak otrzymujesz odwołanie do pliku, a nie tworzysz go, i musisz go przeanalizować, a aby to zrobić, musisz znać separator na platformie. File.separator pomaga to zrobić.


11

OK, sprawdźmy kod.
File.javalinie od 428 do 435 w 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);

I przeczytajmy fs/*(FileSystem)*/.fromURIPath()dokumenty:

java.io.FileSystem
public abstract Łańcuch zURIPath (
ścieżka ciągu) W razie potrzeby należy przetworzyć podany ciąg ścieżki identyfikatora URI. Jest to używane w win32, np. Do przekształcenia „/ c: / foo” w „c: / foo”. Ciąg ścieżki nadal ma separatory ukośnika; kod w klasie File przetłumaczy je po powrocie tej metody.

Oznacza to, że FileSystem.fromURIPath()wykonuje przetwarzanie końcowe ścieżki URI tylko w systemie Windows, a ponieważ w następnym wierszu:

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

Zastępuje każde „/” zależnym od systemu seperatorChar, zawsze możesz być pewien, że „/” jest bezpieczny w każdym systemie operacyjnym.


8

Cóż, jest więcej systemów operacyjnych niż Unix i Windows (urządzenia przenośne itp.), A Java znana jest z przenośności. Najlepszą praktyką jest użycie go, aby JVM mógł określić, który z nich jest najlepszy dla tego systemu operacyjnego.


Większość z tych systemów operacyjnych obsługuje jakiś wariant systemu UNIX. Stare :separatory w stylu Mac już dawno zniknęły. Wygląda na to, że wszyscy oprócz Windows już korzystają ze standardu /. Nawet okna wydają się teraz dobrze obsługiwać ukośniki. Wypróbuj cd /windows/systemsystem Windows 10 z głównego dysku systemowego. Chociaż nadal chcesz wyświetlać ścieżki za pomocą separatora systemu (aby nie mylić użytkowników), możesz po prostu używać ukośnika do przodu /wszędzie i mieć pewność, że Twój kod będzie działał wszędzie tam, gdzie prawdopodobnie go wdrożysz.
Shadow Man

7

Chociaż nie ma to większego znaczenia w drodze powrotnej, robi to w drodze powrotnej.

Na pewno możesz użyć „/” lub „\” w nowym pliku (ścieżka ciągu), ale File.getPath () da ci tylko jeden z nich.


Niewielka korekta ... W systemie Windows można użyć ukośnika /do przodu lub do tyłu \\ . Ale gdziekolwiek indziej, lepiej użyj ukośnika do przodu, /bo będziesz miał problemy.
Shadow Man

6

Późno na imprezę. Korzystam z systemu Windows 10 z JDK 1.8 i Eclipse MARS 1.
Znalazłem to

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

działa i

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

nie działa i

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

nie działa. Dwa ostatnie są równoważne. Więc ... Mam dobry powód, aby NIE używać File.separator.


6
W tym wierszu getClass().getClassLoader().getResourceAsStream("path\to\resource");znajduje się tabulacja ( \t) i znak powrotu karetki ( \r).
Stephan

9
To inny scenariusz niż pytanie. Metoda getResourceAsStream klasyLoader nie przyjmuje ścieżki pliku, ale nazwę zasobu, która może, ale nie musi znajdować się w systemie plików, i jest udokumentowana jako akceptująca tylko „/” jako separator ścieżki zasobów.
daiscog,

@Stephan nie ma śmiesznej ucieczki, ponieważ File.separatorjest to odwrotny ukos . Tylko w zakodowanych ciągach znaków jest traktowany jako znak ucieczki, w którym musisz uciec przed odwrotnym ukośnikiem. Jeśli przechowywane znaku w pliku tekstowym lub w sposób charalbo Stringczym nie trzeba się uciec 2nd czasu, jak to już zostało przekształcone do oczekiwanego znaku backslash. Spróbuj tego, aby przekonać się sam:String backslash = "\\"; System.out.println("welcome" + backslash + "to" + backslash + "reality");
Shadow Man

2
@Stephan och, rozumiem ... Mówiłeś o trzeciej linii. Masz rację. W tym wierszu (łańcuch zakodowany na sztywno) trzeba by było uciec od znaku zmiany znaczenia. Moje oczy zatrzymały się na drugiej linii i na początku nawet nie zauważyłem trzeciej linii.
Shadow Man

3

przenośność prosta i prosta.


Tak, dla przenośności nie używaj ukośnika odwrotnego. Użyj ukośnika do przodu /lub separatora systemu File.separator. Oba wydają się działać wszędzie. Chociaż File.separatorgwarantuje się, że działa wszędzie, /wydaje się , że prosty ukośnik działa również wszędzie. Jeśli gdzieś to nie działa, chciałbym o tym usłyszeć. Wierzę, że będzie działać na wszystkich systemach. Przynajmniej muszę jeszcze znaleźć gdziekolwiek, /co nie działa (Mac OSX, Windows, * nix, Android, iOS - nie sprawdziłem wcześniejszych Maców Mac OS X, które używały „:” jako separatora, OS / 2, NeXT lub inny naprawdę stary system operacyjny).
Shadow Man

1

„Java SE8 dla programistów” twierdzi, że Java poradzi sobie z jednym z nich. (str. 480, ostatni akapit). Przykład twierdzi, że:

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

parsuje się dobrze. Zwróć uwagę na ostatni separator (w stylu uniksowym).

Jest tandetny i prawdopodobnie podatny na błędy, ale tak twierdzą (Deitel i Deitel).

Myślę, że zamieszanie dla ludzi, a nie dla Javy, jest wystarczającym powodem, aby nie korzystać z tej (błędnej?) Funkcji.


1

Jak panowie opisali różnicę wariantami szczegółów.

Chciałbym polecić korzystanie z Apache Commons io api, klasy w FilenameUtilsprzypadku plików w programie z możliwością wdrażania na wielu systemach operacyjnych.


0

Ścieżka do pliku lub katalogu jest określana przy użyciu konwencji nazewnictwa systemu hosta. Jednak klasa File definiuje stałe zależne od platformy, których można używać do obsługi nazw plików i katalogów w sposób niezależny od platformy.

Files.seperator definiuje znak lub ciąg oddzielający katalog i komponenty pliku w nazwie ścieżki. Ten separator to „/”, „\” lub „:” odpowiednio dla systemów Unix, Windows i Macintosh.


„:” Dla komputerów Macintosh jest starożytne. Od czasu OSX Mac używa także „/” (ukośnik), ponieważ działa pod postacią systemu UNIX ze standardowym systemem plików UNIX.
Shadow Man


0

Użycie File.separator zmusiło Ubuntu do generowania plików z „\” w nazwie zamiast katalogów. Może jestem leniwy w tworzeniu plików (i katalogów) i mogłem tego uniknąć, niezależnie od tego, używaj „/” za każdym razem, aby unikać plików z „\” w nazwie


0

Co należy zrobić, jeśli próbujesz utworzyć plik z gotowej ścieżki (zapisanej na przykład w bazie danych) za pomocą separatora systemu Linux?

Może po prostu użyj ścieżki, aby utworzyć plik:

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

Ale system Windows używa innego separatora ( \). Czy zatem alternatywna konwersja separatora ukośnika na platformę jest niezależna? Lubić:

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

Ta metoda convertPathToPlatformIndependentprawdopodobnie będzie podzielona przez „/” i połączona z File.separator.

Cóż, dla mnie to nie jest miłe dla języka niezależnego od platformy (prawda?), A Java już obsługuje użycie /w systemie Windows lub Linux. Ale jeśli pracujesz ze ścieżkami i musisz pamiętać o tej konwersji za każdym razem, będzie to koszmar i nie będziesz miał żadnych rzeczywistych korzyści dla aplikacji w przyszłości (być może we wszechświecie opisanym przez @Pointy).

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.