Diferencia entre File.separator y barra en las rutas

200

¿Cuál es la diferencia entre usar File.separatory un normal /en un Java Path-String?

A diferencia de la \\plataforma de doble barra diagonal inversa , la independencia no parece ser la razón, ya que ambas versiones funcionan en Windows y 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));
    }
}

Para reformular la pregunta, si /funciona en Unix y Windows, ¿por qué debería alguien querer usar File.separator?

Joe23
fuente
55
@Ring 'razones históricas' como ¿qué?
Marqués de Lorne

Respuestas:

246

Con las bibliotecas de Java para manejar archivos, puede usar de forma segura /(barra inclinada, no barra invertida) en todas las plataformas. El código de la biblioteca se encarga de traducir las cosas en rutas específicas de la plataforma internamente.

File.separatorSin embargo, es posible que desee usar en la interfaz de usuario, porque es mejor mostrar a las personas lo que tendrá sentido en su sistema operativo, en lugar de lo que tiene sentido para Java.

Actualización : no he podido, en cinco minutos de búsqueda, encontrar documentado el comportamiento de "siempre se puede usar una barra oblicua". Ahora, estoy seguro de que lo he visto documentado, pero en ausencia de encontrar una referencia oficial (porque mi memoria no es perfecta), me quedaría con el uso File.separatorporque sabes que funcionará.

TJ Crowder
fuente
2
Esto también podría ser un problema con el rendimiento, ya que espera que el separador se convierta en otra cosa en tiempo de ejecución. Además, no espere que esto suceda en todas las JVM no compatibles que existen.
jpabluz
77
@TJ Crowder: "No he podido, en cinco minutos de búsqueda, encontrar el comportamiento documentado 'siempre se puede usar una barra oblicua'". No es una característica de la JVM, es una característica de la API de Windows NT.
Powerlord
12
@Powerlord: si Windows también lo hace, genial, pero la biblioteca (no la JVM) también lo hace. Específicamente, Fileutiliza FileSystem.normalizetodo el lugar para "normalizar" las rutas recibidas a través de la API pública, y casi todo lo que se ocupa de cadenas de ruta de archivo (por ejemplo FileWriter(String)) se utiliza Filedebajo de las cubiertas.
TJ Crowder
9
Desde Java7 ya no es necesario usar File.separator. Es mucho más simple y limpio usar java.nio.file.Paths (Paths.get (primero, más ...)) para la unión de dir a dir y de dir a nombre de archivo.
magiccrafter
66
@jpabluz '¡Un problema con el rendimiento'! ¿En serio? Teniendo en cuenta los usos que se le dan a los nombres de archivo en el disco, el impacto del tiempo de ejecución de una traducción es completamente insignificante. Debe ser compatible con cualquier JVM, ya que es parte de la especificación de File.
Marqués de Lorne
316

Usas File.separatorporque algún día tu programa podría ejecutarse en una plataforma desarrollada en una tierra lejana, una tierra de cosas extrañas y personas extrañas, donde los caballos lloran y las vacas operan todos los ascensores. En esta tierra, la gente ha usado tradicionalmente el carácter ":" como un separador de archivos, y tan obedientemente la JVM obedece sus deseos.

Puntiagudo
fuente
44
Sí, Pointy realmente nos llevó a Elbonia (espero que no tenga un corte de pelo puntiagudo ;-) (juego de palabras geek dentro)
Riduidel
44
"... y las vacas operan todos los ascensores". No me estaba tomando un sorbo de café cuando leí eso. Brillante.
TJ Crowder
8
En ese país, utilizaría la nueva clase org.apache.chicken.elevators.OperatorUtility, que incorpora toda esta locura para su conveniencia.
Cerebro
27

Aunque usar File.separator para hacer referencia a un nombre de archivo es excesivo (para aquellos que imaginan tierras lejanas, imagino que su implementación de JVM reemplazaría a /con un :al igual que el jvm de Windows lo reemplaza con a \).

Sin embargo, a veces obtiene la referencia del archivo, no la crea, y necesita analizarlo, y para poder hacerlo, necesita conocer el separador en la plataforma. File.separator te ayuda a hacer eso.

Yishai
fuente
11

OK, inspeccionemos un código.
File.javalíneas 428 a 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);

Y leamos los fs/*(FileSystem)*/.fromURIPath()documentos:

java.io.FileSystem
public abstract String fromURIPath (ruta de cadena) Postprocese la cadena de ruta de
URI dada si es necesario. Esto se usa en win32, por ejemplo, para transformar "/ c: / foo" en "c: / foo". La cadena de ruta todavía tiene separadores de barras; el código en la clase File los traducirá después de que este método regrese.

Esto significa FileSystem.fromURIPath() que el procesamiento posterior en la ruta URI solo en Windows, y porque en la siguiente línea:

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

Reemplaza cada '/' con un sistema dependiente seperatorChar, siempre puede estar seguro de que '/' es seguro en cada sistema operativo.

Alireza Mohamadi
fuente
8

Bueno, hay más sistemas operativos que Unix y Windows (dispositivos portátiles, etc.), y Java es conocido por su portabilidad. La mejor práctica es usarlo, para que la JVM pueda determinar cuál es el mejor para ese sistema operativo.

jpabluz
fuente
La mayoría de esos sistemas operativos ejecutan alguna variante de UNIX. Los viejos :separadores de estilo Mac han desaparecido hace mucho tiempo. Parece que todos menos Windows usan el estándar /más. E incluso Windows parece manejar bien las barras ahora. Pruebe cd /windows/systemen un sistema Windows 10 desde la unidad del sistema principal. Si bien aún desea mostrar rutas utilizando el separador del sistema (para no confundir a sus usuarios), puede usar la barra diagonal en /cualquier otro lugar y estar seguro de que su código funcionará en cualquier lugar donde pueda implementarlo.
Shadow Man
7

Aunque no hace mucha diferencia en el camino de regreso, sí lo hace en el camino de regreso.

Claro que puede usar '/' o '\' en un nuevo archivo (ruta de cadena), pero File.getPath () solo le dará uno de ellos.

William Billingsley
fuente
Ligera corrección ... En Windows puede usar barra inclinada /hacia adelante o hacia atrás \\ . Pero en cualquier otro lugar, es mejor que uses la barra diagonal /o tendrás problemas.
Shadow Man
6

Tarde a la fiesta. Estoy en Windows 10 con JDK 1.8 y Eclipse MARS 1.
Me parece que

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

funciona y

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

no funciona y

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

No funciona. Los dos últimos son equivalentes. Entonces ... tengo buenas razones para NO usar File.separator.

i-make-robots
fuente
66
En esta línea getClass().getClassLoader().getResourceAsStream("path\to\resource");, hay una tabulación ( \t) y un retorno de carro ( \r).
Stephan
9
Ese es un escenario diferente a la pregunta. El método getResourceAsStream de ClassLoader no toma una ruta de archivo, sino un nombre de recurso que puede o no estar en el sistema de archivos y se documenta que solo acepta '/' como el separador de ruta de recursos.
daiscog
@Stephan no hay escapatoria divertida allí, ya que File.separatores una barra invertida. Es solo en cadenas codificadas donde se trata como un personaje de escape donde necesita escapar de la barra invertida. Si ha almacenado el carácter en un archivo de texto, o en un charo, Stringentonces no necesita escapar por segunda vez ya que ya se ha convertido al carácter de barra invertida esperado. Prueba esto para verlo por ti mismo:String backslash = "\\"; System.out.println("welcome" + backslash + "to" + backslash + "reality");
Shadow Man
2
@ Stephan oh, ya veo ... estabas hablando de la tercera línea. Estás en lo correcto. En esa línea (una cadena codificada) necesitaría escapar del carácter de escape. Mis ojos se detuvieron en la segunda línea y ni siquiera noté la tercera línea al principio.
Shadow Man
3

portabilidad simple y llanamente.

Holograham
fuente
Sí, para portabilidad, no use la barra invertida. Utilice la barra diagonal /o el separador del sistema File.separator. Ambos parecen funcionar en todas partes. MientrasFile.separator está garantizado que funciona en todas partes, la barra simple /también parece funcionar en todas partes. Si no funciona en algún lugar, me encantaría saberlo. Creo que funcionará en todos los sistemas. Por lo menos, aún no he encontrado ningún lugar que /no funcione (Mac OSX, Windows, * nix, Android, iOS; sin embargo, no he comprobado las Macs OSX anteriores que usaban ":" como separador, OS / 2, NeXT, o cualquiera de los otros sistemas operativos realmente antiguos).
Shadow Man
1

"Java SE8 para programadores" afirma que Java hará frente a cualquiera de los dos. (págs. 480, último párrafo). El ejemplo afirma que:

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

analizará muy bien. Tome nota del último separador (estilo Unix).

Es de mal gusto, y probablemente propenso a errores, pero es lo que afirman (Deitel y Deitel).

Creo que la confusión para las personas, en lugar de Java, es razón suficiente para no usar esta función (¿errada?).

Erik Bennett
fuente
1

Como los caballeros describieron la diferencia con detalles variantes.

Me gustaría recomendar el uso de la clase io api de Apache CommonsFilenameUtils cuando se trata de archivos en un programa con la posibilidad de desplegarse en múltiples sistemas operativos.

EX
fuente
0

El nombre de ruta para un archivo o directorio se especifica utilizando las convenciones de nomenclatura del sistema host. Sin embargo, la clase File define constantes dependientes de la plataforma que se pueden usar para manejar nombres de archivos y directorios de manera independiente de la plataforma.

Files.seperator define el carácter o cadena que separa el directorio y los componentes del archivo en un nombre de ruta. Este separador es '/', '\' o ':' para Unix, Windows y Macintosh, respectivamente.

shubhankar
fuente
El ":" para Macintosh es antiguo. Desde OSX, Mac también usa "/" (barra diagonal) ya que ejecuta una forma de UNIX con un sistema de archivos UNIX estándar bajo el capó.
Shadow Man
0

Usando File.separator, Ubuntu generó archivos con "\" en su nombre en lugar de directorios. Tal vez estoy siendo flojo con la forma en que estoy creando archivos (y directorios) y podría haberlo evitado, independientemente, use "/" cada vez para evitar archivos con "\" en su nombre

Guedez
fuente
0

Si está intentando crear un archivo desde una ruta preparada (guardada en la base de datos, por ejemplo) usando el separador de Linux, ¿qué debo hacer?

Tal vez solo use la ruta para crear el archivo:

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

Pero Windows usa un separador diferente ( \). Entonces, ¿la alternativa es convertir el separador de barras en una plataforma independiente? Me gusta:

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

Este método convertPathToPlatformIndependentprobablemente tendrá algún tipo de división por "/" y se unirá con File.separator.

Bueno, para mí, eso no es bueno para un lenguaje que es independiente de la plataforma (¿verdad?) Y Java ya es compatible /con Windows o Linux. Pero si está trabajando con rutas y necesita recordar esta conversión cada vez, esto será una pesadilla y no tendrá ninguna ganancia real para la aplicación en el futuro (tal vez en el universo que describió @Pointy).

Dherik
fuente