Unterschied zwischen File.separator und Schrägstrich in Pfaden

200

Was ist der Unterschied zwischen der Verwendung File.separatorund einer normalen/ in einem Java Path-String?

Im Gegensatz zur doppelten Backslash- \\Plattform scheint die Unabhängigkeit nicht der Grund zu sein, da beide Versionen unter Windows und Unix funktionieren.

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

Um die Frage neu zu formulieren: Wenn es /unter Unix und Windows funktioniert, warum sollte man es jemals verwenden wollen File.separator?

Joe23
quelle
5
@Ring 'Historische Gründe' wie was?
Marquis von Lorne

Antworten:

245

Mit den Java-Bibliotheken für den Umgang mit Dateien können Sie sicher /(Schrägstrich, nicht Backslash) auf allen Plattformen verwenden. Der Bibliothekscode behandelt die interne Übersetzung von Dingen in plattformspezifische Pfade.

Möglicherweise möchten Sie es jedoch File.separatorin der Benutzeroberfläche verwenden, da es am besten ist, den Benutzern zu zeigen, was in ihrem Betriebssystem sinnvoll ist und nicht, was für Java sinnvoll ist.

Update : Ich konnte in fünf Minuten der Suche das dokumentierte Verhalten "Sie können immer einen Schrägstrich verwenden" nicht finden. Ich bin mir sicher, dass ich es dokumentiert gesehen habe, aber da ich keine offizielle Referenz gefunden habe (weil mein Gedächtnis nicht perfekt ist), würde ich bei der Verwendung bleiben, File.separatorweil Sie wissen, dass das funktionieren wird.

TJ Crowder
quelle
2
Dies kann auch ein Problem mit der Leistung sein, da Sie erwarten, dass das Trennzeichen zur Laufzeit in etwas anderes konvertiert wird. Erwarten Sie auch nicht, dass dies in allen nicht unterstützten JVMs da draußen passiert.
Jpabluz
7
@TJ Crowder: "Ich war in fünf Minuten der Suche nicht in der Lage, das dokumentierte Verhalten" Sie können immer einen Schrägstrich verwenden "zu finden." Es ist keine Funktion der JVM, sondern eine Funktion der Windows NT-API.
Powerlord
12
@ Powerlord: Wenn Windows es auch macht, großartig - aber die Bibliothek (nicht die JVM) macht es auch. Insbesondere Fileverwendet der FileSystem.normalizeganzen Ort zu „normalisieren“ Wege über die öffentliche API empfangen, und fast alles , was die sich mit Dateipfad Strings (zum Beispiel FileWriter(String)) Anwendungen Fileunter der Decke.
TJ Crowder
9
Seit Java7 muss File.separator nicht mehr verwendet werden. Es ist viel einfacher und sauberer, java.nio.file.Paths (Paths.get (first, more ...)) für die Verknüpfung von dir zu dir und dir zu filename zu verwenden.
Magiccrafter
6
@jpabluz 'Ein Problem mit der Leistung'! Sind Sie im Ernst? In Anbetracht der Verwendung von Dateinamen auf der Festplatte ist die Laufzeitauswirkung einer Übersetzung äußerst unbedeutend. Es sollte von jeder JVM unterstützt werden, da es Teil der Spezifikation von ist File.
Marquis von Lorne
316

Sie verwenden, File.separatorweil Ihr Programm eines Tages möglicherweise auf einer Plattform ausgeführt wird, die in einem fernen Land entwickelt wurde, einem Land mit seltsamen Dingen und fremden Menschen, in dem Pferde weinen und Kühe alle Aufzüge bedienen. In diesem Land haben die Menschen traditionell das Zeichen ":" als Dateitrennzeichen verwendet, und so gehorcht die JVM pflichtbewusst ihren Wünschen.

Spitze
quelle
4
Ja, Pointy hat uns wirklich in Elbonia mitgenommen (ich hoffe, er hat keinen spitzen Haarschnitt ;-) (Geek-Wortspiel drinnen)
Riduidel
4
"... und Kühe bedienen alle Aufzüge." Genauso gut nahm ich keinen Schluck von meinem Kaffee, als ich das las. Brillant.
TJ Crowder
8
In einem solchen Land würden Sie die neue Klasse org.apache.chicken.elevators.OperatorUtility verwenden, die all diese Verrücktheit für Ihre Bequemlichkeit einbettet.
Gehirn
27

Obwohl File.separator mit einem Dateinamen referenzieren Overkill ist (für diejenigen , die fernen Ländern vorstellen, stelle ich mir ihre JVM Implementierung eine ersetzen würde /mit :genau wie die Fenster Jvm ersetzt mit einer es \).

Manchmal erhalten Sie jedoch die Dateireferenz, erstellen sie nicht und müssen sie analysieren. Um dies tun zu können, müssen Sie das Trennzeichen auf der Plattform kennen. File.separator hilft Ihnen dabei.

Yishai
quelle
11

OK, lassen Sie uns einen Code untersuchen.
File.javaZeilen 428 bis 435 in 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);

Und lesen wir die fs/*(FileSystem)*/.fromURIPath()Dokumente:

java.io.FileSystem
public abstract String fromURIPath (String path)
Verarbeiten Sie gegebenenfalls die angegebene URI- Pfadzeichenfolge nach . Dies wird unter win32 verwendet, um beispielsweise "/ c: / foo" in "c: / foo" umzuwandeln. Die Pfadzeichenfolge enthält weiterhin Schrägstriche. Code in der File-Klasse übersetzt sie, nachdem diese Methode zurückgegeben wurde.

Dies bedeutet, dass FileSystem.fromURIPath()die Nachbearbeitung im URI-Pfad nur unter Windows erfolgt und in der nächsten Zeile:

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

Es ersetzt jedes '/' durch systemabhängig seperatorChar. Sie können immer sicher sein, dass '/' in jedem Betriebssystem sicher ist .

Alireza Mohamadi
quelle
8

Nun, es gibt mehr Betriebssysteme als Unix und Windows (tragbare Geräte usw.), und Java ist für seine Portabilität bekannt. Die beste Vorgehensweise besteht darin, es zu verwenden, damit die JVM ermitteln kann, welches für dieses Betriebssystem am besten geeignet ist.

jpabluz
quelle
Die meisten dieser Betriebssysteme führen eine UNIX-Variante aus. Die alten :Trennzeichen im Mac-Stil sind längst verschwunden. Es scheint, dass alle außer Windows den Standard /nicht mehr verwenden. Und selbst Fenster scheinen jetzt gut mit Schrägstrichen umzugehen. Probieren Sie cd /windows/systemein Windows 10-System von Ihrem Hauptsystemlaufwerk aus. Während Sie weiterhin Pfade mithilfe des Systemtrennzeichens anzeigen möchten (um Ihre Benutzer nicht zu verwirren), können Sie /überall nur Schrägstriche verwenden und sicher sein, dass Ihr Code überall dort funktioniert, wo Sie ihn wahrscheinlich bereitstellen.
Shadow Man
7

Auf dem Rückweg macht es zwar keinen großen Unterschied, aber auf dem Rückweg.

Natürlich können Sie entweder '/' oder '\' in einer neuen Datei (String-Pfad) verwenden, aber File.getPath () gibt Ihnen nur eine davon.

William Billingsley
quelle
Leichte Korrektur ... In Windows können Sie entweder Schrägstriche /oder \\ Schrägstriche verwenden. Aber woanders verwenden Sie besser Schrägstriche, sonst treten /Probleme auf.
Shadow Man
6

Spät zur Party. Ich bin auf Windows 10 mit JDK 1.8 und Eclipse MARS 1.
Ich finde das

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

funktioniert und

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

funktioniert nicht und

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

funktioniert nicht. Die letzten beiden sind gleichwertig. Also ... ich habe guten Grund, File.separator NICHT zu verwenden.

i-make-robots
quelle
6
In dieser Zeile getClass().getClassLoader().getResourceAsStream("path\to\resource");gibt es eine Tabelle ( \t) und einen Wagenrücklauf ( \r).
Stephan
9
Das ist ein anderes Szenario als die Frage. Die getResourceAsStream-Methode von ClassLoader verwendet keinen Dateipfad, sondern einen Ressourcennamen, der sich möglicherweise im Dateisystem befindet oder nicht und dokumentiert ist , dass nur '/' als Trennzeichen für den Ressourcenpfad akzeptiert wird.
Daiscog
@Stephan gibt es dort kein lustiges Entkommen, da File.separatores einen Backslash gibt. Nur in fest codierten Zeichenfolgen wird es als Escape-Zeichen behandelt, bei dem Sie dem Backslash entkommen müssen. Wenn Sie das Zeichen in einer Textdatei oder in einem charoder gespeichert haben, Stringmüssen Sie es nicht ein zweites Mal maskieren, da es bereits in das erwartete Backslash-Zeichen konvertiert wurde. Versuchen Sie dies, um sich selbst davon zu überzeugen:String backslash = "\\"; System.out.println("welcome" + backslash + "to" + backslash + "reality");
Shadow Man
2
@Stephan oh, ich verstehe ... Du hast über die 3. Zeile gesprochen. Du hast Recht. In dieser Zeile (eine fest codierte Zeichenfolge) müssten Sie das Escape-Zeichen maskieren. Meine Augen blieben bei der 2. Zeile stehen und ich bemerkte die 3. Zeile zuerst nicht einmal.
Shadow Man
3

Portabilität schlicht und einfach.

Holograham
quelle
Ja, für die Portabilität, nicht nicht verwenden Backslash. Verwenden Sie einen Schrägstrich /oder das Systemtrennzeichen File.separator. Beide scheinen überall zu funktionieren. Während File.separatorgarantiert überall funktioniert, /scheint der einfache Schrägstrich auch überall zu funktionieren. Wenn es irgendwo nicht funktioniert, würde ich gerne davon hören. Ich glaube, dass es auf allen Systemen funktionieren wird. Zumindest habe ich noch keinen Ort gefunden, /der nicht funktioniert (Mac OSX, Windows, * nix, Android, iOS - ich habe vor OSX Macs, die ":" als Trennzeichen verwendet haben, OS / nicht überprüft, OS / 2, NeXT oder eines der anderen wirklich alten Betriebssysteme).
Shadow Man
1

"Java SE8 für Programmierer" behauptet, dass Java mit beiden fertig wird. (S. 480, letzter Absatz). Das Beispiel behauptet, dass:

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

wird gut analysieren. Beachten Sie das letzte (Unix-artige) Trennzeichen.

Es ist klebrig und wahrscheinlich fehleranfällig, aber es ist das, was sie (Deitel und Deitel) behaupten.

Ich denke, die Verwirrung für die Menschen und nicht für Java ist Grund genug, diese (falsche?) Funktion nicht zu verwenden.

Erik Bennett
quelle
1

Wie die Herren den Unterschied mit Variantendetails beschrieben haben.

Ich möchte die Verwendung der Apache Commons io api-Klasse empfehlen , FilenameUtilswenn Dateien in einem Programm mit der Möglichkeit der Bereitstellung auf mehreren Betriebssystemen verarbeitet werden.

EX
quelle
0

Der Pfadname für eine Datei oder ein Verzeichnis wird anhand der Namenskonventionen des Hostsystems angegeben. Die File-Klasse definiert jedoch plattformabhängige Konstanten, mit denen Datei- und Verzeichnisnamen plattformunabhängig behandelt werden können.

Files.seperator definiert das Zeichen oder die Zeichenfolge, die das Verzeichnis und die Dateikomponenten in einem Pfadnamen trennt. Dieses Trennzeichen lautet '/', '\' oder ':' für Unix, Windows und Macintosh.

Shubhankar
quelle
Das ":" für Macintosh ist uralt. Seit OSX verwendet Mac auch "/" (Schrägstrich), da eine UNIX-Form mit einem Standard-UNIX-Dateisystem unter der Haube ausgeführt wird.
Shadow Man
0

Mit File.separator hat Ubuntu Dateien mit dem Namen "\" anstelle von Verzeichnissen generiert. Vielleicht bin ich faul, wie ich Dateien (und Verzeichnisse) erstelle, und hätte es vermeiden können, unabhängig davon, jedes Mal "/" zu verwenden, um Dateien mit "\" im Namen zu vermeiden

Guedez
quelle
0

Was kann ich tun, wenn Sie versuchen, eine Datei aus einem fertigen Pfad (z. B. in einer Datenbank gespeichert) mit dem Linux-Trennzeichen zu erstellen?

Vielleicht verwenden Sie einfach den Pfad, um die Datei zu erstellen:

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

Windows verwendet jedoch ein anderes Trennzeichen ( \). Ist die Alternative, den Schrägstrich-Separator in eine plattformunabhängige umzuwandeln? Mögen:

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

Diese Methode convertPathToPlatformIndependent wahrscheinlich durch "/" geteilt und mit File.separator verbunden.

Für mich ist das nicht gut für eine Sprache, die plattformunabhängig ist (oder?) Und Java unterstützt bereits die Verwendung /unter Windows oder Linux. Wenn Sie jedoch mit Pfaden arbeiten und sich jedes Mal an diese Konvertierung erinnern müssen, ist dies ein Albtraum und Sie werden in Zukunft keinen wirklichen Gewinn für die Anwendung haben (möglicherweise in dem von @Pointy beschriebenen Universum).

Dherik
quelle