¿Cómo resuelve Java una ruta relativa en new File ()?


Estoy tratando de entender la forma en que Java resuelve la ruta relativa al crear un objeto File.

Sistema operativo utilizado: Windows

Para el siguiente fragmento, estoy obteniendo un IOException ya que no puede encontrar la ruta:

@Test
public void testPathConversion() {
        File f = new File("test/test.txt");
        try {
            f.createNewFile();
            System.out.println(f.getPath());
            System.out.println(f.getAbsolutePath());    
            System.out.println(f.getCanonicalPath());
        } catch (Exception e) {
            e.printStackTrace();
        }
}

Lo que entiendo aquí es que Java trata la ruta proporcionada como absoluta y devuelve un error cuando la ruta no existe. Así que tiene sentido.

Cuando actualizo el código anterior para usar la ruta relativa:

@Test
    public void testPathConversion() {
        File f = new File("test/../test.txt");
        try {
            f.createNewFile();
            System.out.println(f.getPath());
            System.out.println(f.getAbsolutePath());    
            System.out.println(f.getCanonicalPath());
        } catch (Exception e) {
            e.printStackTrace();
        }    
    }

Crea un nuevo archivo y proporciona la siguiente salida:

test\..\test.txt
C:\JavaForTesters\test\..\test.txt
C:\JavaForTesters\test.txt

En este caso, mi suposición es, a pesar de que la ruta proporcionada no existe, porque la ruta contiene "/../ ", java trata esto como una ruta relativa y crea el archivo en el user.dir. Así que esto también tiene sentido.

Pero si actualizo la ruta relativa como se muestra a continuación:

   @Test
    public void testPathConversion() {
        File f = new File("test/../../test.txt");
        try {
            f.createNewFile();
            System.out.println(f.getPath());
            System.out.println(f.getAbsolutePath());
            System.out.println(f.getCanonicalPath());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Entonces obtengo IOException: El acceso está denegado.

Mis preguntas son:

  1. por qué "test/../test.txt" se trata como una ruta relativa y crea el archivo en "user.dir" pero "test/../../test.txt" devuelve un error? ¿Dónde intenta crear el archivo para la ruta "test/../../test.txt"?
  2. Cuando no se encuentra la ruta relativa especificada, el archivo parece estar creado en user.dir. Por lo tanto, me parece que los dos escenarios siguientes hacen lo mismo:

    //scenario 1
    File f = new File("test/../test.txt");
    f.createNewFile();
    
    //scenario 2
    File f = new File("test.txt");
    f.createNewFile();
    

Entonces, ¿hay un caso del mundo real en el que uno usaría el escenario 1 en lugar del escenario 2?

Supongo que me estoy perdiendo algo obvio aquí o he malentendido fundamentalmente los caminos relativos. Fui a través de los documentos de Java para el archivo y no soy capaz de encontrar una explicación para esto. Hay bastantes preguntas publicadas en Stack Overflow con respecto a las rutas relativas, pero las que busqué fueron para escenarios específicos y no exactamente sobre cómo se resuelven las rutas relativas.

Sería genial si alguien pudiera explicarme cómo funciona esto o señalar algunos enlaces relacionados.

Author: Andrew Thompson, 2014-01-11

6 answers

Hay un concepto de working directory.
Este directorio está representado por un . (punto).
En rutas relativas, todo lo demás es relativo a ella.

En pocas palabras, el . (el directorio de trabajo) es donde se ejecuta el programa.
En algunos casos se puede cambiar el directorio de trabajo, pero en general esto es
lo que representa el punto. Creo que esto es C:\JavaForTesters\ en su caso.

Así que test\..\test.txt significa: el subdirectorio test
en mi directorio de trabajo, luego un nivel arriba, entonces el
file test.txt. Esto es básicamente lo mismo que solo test.txt.

Para más detalles, consulte aquí.

Http://docs.oracle.com/javase/7/docs/api/java/io/File.html

Http://docs.oracle.com/javase/tutorial/essential/io/pathOps.html

 17
Author: peter.petrov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-11 10:26:28

Cuando su ruta comienza con un directorio raíz, es decir, C:\ en windows o / en Unix o en la ruta de recursos de java, se considera una ruta absoluta. Todo lo demás es relativo, así que

new File("test.txt") is the same as new File("./test.txt")

new File("test/../test.txt") is the same as new File("./test/../test.txt")

La principal diferencia entre getAbsolutePath y getCanonicalPath es que el primero concatena un camino padre y un camino hijo, por lo que puede contener puntos: .. o .. getCanonicalPath siempre devolverá la misma ruta para un archivo en particular.

Nota: File.equals utiliza una forma abstracta de una ruta (getAbsolutePath) para comparar archivos, así que esto significa que dos Fileobjetos para el mismo podrían no ser iguales y File s no son seguros para usar en colecciones como Map o Set.

 9
Author: Andrey Chaschev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-15 17:29:24

El directorio de trabajo es un concepto común en prácticamente todos los sistemas operativos y lenguajes de programas, etc. Es el directorio en el que se está ejecutando el programa. Esto suele ser (pero no siempre, hay formas de cambiarlo) el directorio en el que se encuentra la aplicación.

Las rutas relativas son aquellas que comienzan sin un especificador de unidad. Así que en Linux no comienzan con un /, en Windows no comienzan con un C:\, etc. Estos siempre comienzan desde su directorio de trabajo.

Absoluto las rutas son las que comienzan con un especificador de unidad (o máquina para rutas de red). Siempre van desde el inicio de ese viaje.

 5
Author: Tim B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-11 10:18:50

En windows y Netbeans puede establecer la ruta relativa como:

    new FileReader("src\\PACKAGE_NAME\\FILENAME");

En Linux y Netbeans puede establecer la ruta relativa como:

    new FileReader("src/PACKAGE_NAME/FILENAME");

Si tienes tu código dentro Source Packages No sé si es lo mismo para eclipse u otro IDE

 0
Author: Ricard Molins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-12 10:42:03

Solo está ligeramente relacionado con la pregunta, pero trata de envolver tu cabeza alrededor de esta. Así que no intuitivo:

import java.nio.file.*;
class Main {
  public static void main(String[] args) {
    Path p1 = Paths.get("/personal/./photos/./readme.txt");
    Path p2 = Paths.get("/personal/index.html");
    Path p3 = p1.relativize(p2);
    System.out.println(p3); //prints  ../../../../index.html  !!
  }
}
 0
Author: djangofan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-10 18:48:32

Las rutas relativas pueden entenderse mejor si sabe cómo Java ejecuta el programa.

Existe un concepto de directorio de trabajo cuando se ejecutan programas en Java. Asumiendo que tienes una clase, digamos, FileHelper que hace el IO bajo /User/home/Desktop/projectRoot/src/topLevelPackage/.

Dependiendo del caso en el que invoque java para ejecutar el programa, tendrá un directorio de trabajo diferente. Si ejecuta su programa desde dentro y desde el IDE, lo más probable es que sea projectRoot.

  • En este caso $ projectRoot/src : java topLevelPackage.FileHelper será src.

  • En este caso $ projectRoot : java -cp src topLevelPackage.FileHelper será projectRoot.

  • En este caso $ /User/home/Desktop : java -cp ./projectRoot/src topLevelPackage.FileHelper será Desktop.

(Assuming $ is your command prompt with standard Unix-like FileSystem. Similar correspondence/parallels with Windows system)

Por lo tanto, su ruta relativa raíz (.) se resuelve en su directorio de trabajo. Por lo tanto, para estar mejor seguro de dónde escribir archivos, se dice que considere el enfoque a continuación.

package topLevelPackage

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;

public class FileHelper {

    // Not full implementation, just barebone stub for path
    public void createLocalFile() {

        // Explicitly get hold of working directory
        String workingDir = System.getProperty("user.dir");

        Path filePath = Paths.get(workingDir+File.separator+"sampleFile.txt");

        // In case we need specific path, traverse that path, rather using . or .. 
        Path pathToProjectRoot = Paths.get(System.getProperty("user.home"), "Desktop", "projectRoot");

        System.out.println(filePath);
        System.out.println(pathToProjectRoot);

    }
}

Espero que esto ayude.

 0
Author: Ravi Tiwari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-22 16:55:58