Différence entre File.separator et slash dans les chemins

200

Quelle est la différence entre l'utilisation File.separator et une normale /dans une chaîne de chemin Java?

Contrairement à l' \\indépendance de la plate-forme à double barre oblique inverse ne semble pas être la raison, car les deux versions fonctionnent sous Windows et 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));
    }
}

Pour reformuler la question, si cela /fonctionne sous Unix et Windows, pourquoi devrait-on jamais vouloir l'utiliser File.separator?

Joe23
la source
5
@Ring 'Raisons historiques' comme quoi?
Marquis de Lorne le

Réponses:

246

Avec les bibliothèques Java pour traiter les fichiers, vous pouvez utiliser en toute sécurité /(barre oblique, pas barre oblique inverse) sur toutes les plates-formes. Le code de bibliothèque gère la traduction des choses en chemins spécifiques à la plate-forme en interne.

Vous voudrez peut-être utiliser File.separatordans l'interface utilisateur, car il est préférable de montrer aux gens ce qui aura du sens dans leur système d'exploitation, plutôt que ce qui est logique pour Java.

Mise à jour : Je n'ai pas pu, en cinq minutes de recherche, trouver le comportement "vous pouvez toujours utiliser une barre oblique" documenté. Maintenant, je suis sûr que je l'ai vu documenté, mais en l'absence de trouver une référence officielle (parce que ma mémoire n'est pas parfaite), je m'en tiendrai à l'utilisation File.separatorparce que vous savez que cela fonctionnera.

TJ Crowder
la source
2
Cela peut également être un problème avec les performances, car vous vous attendez à ce que le séparateur soit converti en autre chose au moment de l'exécution. En outre, ne vous attendez pas à ce que cela se produise dans toutes les JVM non prises en charge.
jpabluz
7
@TJ Crowder: "Je n'ai pas pu, en cinq minutes de recherche, trouver le comportement" vous pouvez toujours utiliser une barre oblique "documenté." Ce n'est pas une fonctionnalité de la JVM, c'est une fonctionnalité de l'API Windows NT.
Powerlord
12
@Powerlord: Si Windows le fait aussi, tant mieux - mais la bibliothèque (pas la JVM) le fait aussi. Plus précisément, Fileutilise FileSystem.normalizepartout pour «normaliser» les chemins reçus via l'API publique, et presque tout ce qui concerne les chaînes de chemin de fichier (par exemple, FileWriter(String)) utilise Filesous les couvertures.
TJ Crowder
9
Depuis Java7, il n'est plus nécessaire d'utiliser File.separator. Il est beaucoup plus simple et plus propre d'utiliser java.nio.file.Paths (Paths.get (d'abord, plus ...)) pour joindre dir à dir et dir à nom de fichier.
magiccrafter
6
@jpabluz 'Un problème de performances'! Es-tu sérieux? Compte tenu des utilisations des noms de fichiers sur le disque, l'impact sur l'exécution d'une traduction est tout à fait insignifiant. Il doit être pris en charge par n'importe quelle machine virtuelle Java, car il fait partie de la spécification de File.
Marquis de Lorne
316

Vous utilisez File.separatorparce qu'un jour votre programme pourrait fonctionner sur une plate-forme développée dans un pays lointain, un pays de choses étranges et de personnes étrangères, où les chevaux pleurent et les vaches exploitent tous les ascenseurs. Dans ce pays, les gens ont traditionnellement utilisé le caractère ":" comme séparateur de fichiers, et la JVM obéit donc consciencieusement à leurs souhaits.

Pointu
la source
4
Ouaip, Pointy nous emmène vraiment à Elbonia (j'espère qu'il n'a pas de coupe de cheveux pointue ;-) (jeu de mots geek à l'intérieur)
Riduidel
4
"... et les vaches exploitent tous les ascenseurs." Tout aussi bien, je ne buvais pas une gorgée de café en lisant cela. Brillant.
TJ Crowder
8
Dans un tel pays, vous utiliseriez la nouvelle classe org.apache.chicken.elevators.OperatorUtility, qui intègre toute cette folie pour votre commodité.
Brain
27

Bien que l'utilisation de File.separator pour référencer un nom de fichier soit exagérée (pour ceux qui imaginent des contrées lointaines, j'imagine que leur implémentation JVM remplacerait un /par un :comme les fenêtres jvm le remplace par un\ ).

Cependant, parfois vous obtenez la référence du fichier, vous ne la créez pas, et vous devez l'analyser, et pour pouvoir le faire, vous devez connaître le séparateur sur la plate-forme. File.separator vous aide à le faire.

Yishai
la source
11

OK, inspectons du code.
File.javalignes 428 à 435 en 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);

Et lisons les fs/*(FileSystem)*/.fromURIPath()documents:

java.io.FileSystem
public abstract String fromURIPath (String path)
Post-traiter la chaîne de chemin URI donnée si nécessaire. Ceci est utilisé sur win32, par exemple, pour transformer "/ c: / foo" en "c: / foo". La chaîne de chemin d'accès comporte toujours des séparateurs de barre oblique; le code de la classe File les traduira après le retour de cette méthode.

Cela signifie FileSystem.fromURIPath()que le post-traitement sur le chemin URI est uniquement sous Windows, et parce que dans la ligne suivante:

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

Il remplace chaque «/» par un système dépendant seperatorChar, vous pouvez toujours être sûr que «/» est sûr dans tous les systèmes d'exploitation.

Alireza Mohamadi
la source
8

Eh bien, il y a plus de systèmes d'exploitation que Unix et Windows (appareils portables, etc.), et Java est connu pour sa portabilité. La meilleure pratique consiste à l'utiliser, afin que la machine virtuelle Java puisse déterminer laquelle est la meilleure pour ce système d'exploitation.

jpabluz
la source
La plupart de ces systèmes d'exploitation exécutent une variante d'UNIX. Les anciens :séparateurs de style Mac ont depuis longtemps disparu. Il semble que tout le monde sauf Windows utilise la norme /. Et même les fenêtres semblent bien gérer les barres obliques maintenant. Essayez cd /windows/systemun système Windows 10 à partir de votre lecteur système principal. Bien que vous souhaitiez toujours afficher les chemins à l'aide du séparateur système (afin de ne pas confondre vos utilisateurs), vous pouvez simplement utiliser la barre oblique /partout ailleurs et être sûr que votre code fonctionnera partout où vous êtes susceptible de le déployer.
Shadow Man
7

Bien que cela ne fasse pas beaucoup de différence sur le chemin du retour, il le fait sur le chemin du retour.

Bien sûr, vous pouvez utiliser '/' ou '\' dans le nouveau fichier (chemin de chaîne), mais File.getPath () ne vous en donnera qu'un seul.

William Billingsley
la source
Légère correction ... Dans Windows, vous pouvez utiliser une barre oblique /vers l' avant ou vers l'arrière \\ . Mais partout ailleurs, vous feriez mieux d'utiliser la barre oblique /ou vous aurez des problèmes.
Shadow Man
6

Tard à la fête. Je suis sur Windows 10 avec JDK 1.8 et Eclipse MARS 1.
Je trouve que

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

fonctionne et

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

ne fonctionne pas et

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

ne marche pas. Les deux derniers sont équivalents. Donc ... j'ai de bonnes raisons de NE PAS utiliser File.separator.

i-make-robots
la source
6
Dans cette ligne getClass().getClassLoader().getResourceAsStream("path\to\resource");, il y a une tabulation ( \t) et un retour chariot ( \r).
Stephan
9
C'est un scénario différent de la question. La méthode getResourceAsStream de ClassLoader ne prend pas un chemin de fichier, mais un nom de ressource qui peut ou non se trouver sur le système de fichiers et est documenté comme n'acceptant que «/» comme séparateur de chemin de ressource.
daiscog
@Stephan il n'y a pas de drôle de fuite, car File.separatorc'est une barre oblique inverse. Ce n'est que dans les chaînes codées en dur où il est traité comme un caractère d'échappement où vous devez échapper à la barre oblique inverse. Si vous avez stocké le caractère dans un fichier texte, ou dans un charou Stringalors vous n'avez pas besoin de l'échapper une deuxième fois car il a déjà été converti en barre oblique inverse attendue. Essayez ceci pour voir par vous-même:String backslash = "\\"; System.out.println("welcome" + backslash + "to" + backslash + "reality");
Shadow Man
2
@Stephan oh, je vois ... Tu parlais de la 3ème ligne. Vous avez raison. Dans cette ligne (une chaîne codée en dur), vous devez échapper au caractère d'échappement. Mes yeux se sont arrêtés à la 2ème ligne et je n'ai même pas remarqué la 3ème ligne au début.
Shadow Man
3

portabilité claire et simple.

Holograham
la source
Oui, pour la portabilité, n'utilisez pas de barre oblique inverse. Utilisez une barre oblique /ou le séparateur système File.separator. Ces deux éléments semblent fonctionner partout. Bien qu'il File.separatorsoit garanti de fonctionner partout, la simple barre oblique /semble également fonctionner partout. Si cela ne fonctionne pas quelque part, j'aimerais en entendre parler. Je crois que cela fonctionnera sur tous les systèmes. À tout le moins, je n'ai pas encore trouvé d'endroit qui /ne fonctionne pas (Mac OSX, Windows, * nix, Android, iOS - je n'ai pas vérifié les Mac OSX antérieurs qui utilisaient ":" comme séparateur, OS / 2, NeXT, ou l'un des autres OS vraiment anciens).
Shadow Man
1

"Java SE8 for Programmers" prétend que Java va faire face à l'un ou l'autre. (p. 480, dernier paragraphe). L'exemple affirme que:

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

analysera très bien. Prenez note du dernier séparateur (de style Unix).

C'est collant et probablement sujet aux erreurs, mais c'est ce qu'ils prétendent (Deitel et Deitel).

Je pense que la confusion pour les gens, plutôt que pour Java, est une raison suffisante pour ne pas utiliser cette fonctionnalité (mis?).

Erik Bennett
la source
1

Comme les messieurs ont décrit la différence avec les détails des variantes.

Je voudrais recommander l'utilisation de la classe Apache Commons io api, FilenameUtilslorsque vous traitez des fichiers dans un programme avec la possibilité de déployer sur plusieurs OS.

EX
la source
0

Le chemin d'accès d'un fichier ou d'un répertoire est spécifié à l'aide des conventions de dénomination du système hôte. Cependant, la classe File définit des constantes dépendantes de la plateforme qui peuvent être utilisées pour gérer les noms de fichiers et de répertoires d'une manière indépendante de la plateforme.

Files.seperator définit le caractère ou la chaîne qui sépare le répertoire et les composants du fichier dans un nom de chemin. Ce séparateur est '/', '\' ou ':' pour Unix, Windows et Macintosh, respectivement.

shubhankar
la source
Le ":" pour Macintosh est ancien. Depuis OSX, Mac utilise également "/" (barre oblique) car il exécute une forme UNIX avec un système de fichiers UNIX standard sous le capot.
Shadow Man
0

L'utilisation de File.separator a permis à Ubuntu de générer des fichiers avec "\" sur son nom au lieu de répertoires. Peut-être que je suis paresseux avec la façon dont je crée des fichiers (et répertoires) et que j'aurais pu l'éviter, malgré tout, utilisez "/" à chaque fois pour éviter les fichiers avec "\" sur son nom

Guedez
la source
0

Si vous essayez de créer un fichier à partir d'un chemin prêt (enregistré dans la base de données, par exemple) à l'aide du séparateur Linux, que dois-je faire?

Peut-être utilisez-vous simplement le chemin pour créer le fichier:

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

Mais Windows utilise un séparateur différent ( \). Alors, l'alternative est-elle de convertir le séparateur de barres obliques en plateforme indépendante? Comme:

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

Cette méthode convertPathToPlatformIndependent aura probablement une sorte de séparation par "/" et se joindra à File.separator.

Eh bien, pour moi, ce n'est pas bien pour un langage indépendant de la plate-forme (non?) Et Java prend déjà en charge l'utilisation de /Windows ou Linux. Mais si vous travaillez avec des chemins et devez vous souvenir de cette conversion à chaque fois, ce sera un cauchemar et vous n'aurez aucun gain réel pour l'application sur le futur (peut-être dans l'univers décrit par @Pointy).

Dherik
la source