recurso abierto con ruta relativa en Java

84

En mi aplicación Java, necesito obtener algunos archivos y directorios.

Esta es la estructura del programa:

./main.java
./package1/guiclass.java
./package1/resources/resourcesloader.java
./package1/resources/repository/modules/   -> this is the dir I need to get
./package1/resources/repository/SSL-Key/cert.jks    -> this is the file I need to get

guiclass carga la clase de cargador de recursos que cargará mis recursos (directorio y archivo).

En cuanto al archivo, intenté

resourcesloader.class.getClass().getResource("repository/SSL-Key/cert.jks").toString()

para obtener el camino real, pero de esta manera no funciona.

No tengo idea de qué ruta usar para el directorio.

Giancarlo
fuente
1
class.getClass () no es lo mismo que class.getClassLoader (). También hay otra solución, getResourceAsStream () usando una clase en el mismo paquete que su recurso. Para más detalles: tshikatshikaaa.blogspot.nl/2012/07/… .
Jérôme Verstrynge

Respuestas:

48

Proporcione la ruta relativa al cargador de clases, no la clase de la que obtiene el cargador. Por ejemplo:

resourcesloader.class.getClassLoader().getResource("package1/resources/repository/SSL-Key/cert.jks").toString();
jonathan.cone
fuente
161

Tuve problemas con el uso del getClass().getResource("filename.txt")método. Al leer las instrucciones de los documentos de Java, si su recurso no está en el mismo paquete que la clase desde la que está tratando de acceder al recurso, entonces debe darle una ruta relativa que comience con '/'. La estrategia recomendada es colocar sus archivos de recursos en una carpeta de "recursos" en el directorio raíz. Entonces, por ejemplo, si tiene la estructura:

src/main/com/mycompany/myapp

luego puede agregar una carpeta de recursos según lo recomendado por maven en:

src/main/resources

además, puede agregar subcarpetas en la carpeta de recursos

src/main/resources/textfiles

y decir que su archivo se llama myfile.txtpara que tenga

src/main/resources/textfiles/myfile.txt

Aquí es donde entra en juego el estúpido problema de la ruta. Digamos que tiene una clase en su com.mycompany.myapp packagey desea acceder al myfile.txtarchivo desde su carpeta de recursos. Algunos dicen que necesitas dar el:

"/main/resources/textfiles/myfile.txt" path

o

"/resources/textfiles/myfile.txt"

ambos están equivocados. Después de ejecutar mvn clean compile, los archivos y carpetas se copian en:

myapp/target/classes 

carpeta. Pero la carpeta de recursos no está allí, solo las carpetas en la carpeta de recursos. Así que tienes:

myapp/target/classes/textfiles/myfile.txt

myapp/target/classes/com/mycompany/myapp/*

entonces la ruta correcta para darle al getClass().getResource("")método es:

"/textfiles/myfile.txt"

aquí está:

getClass().getResource("/textfiles/myfile.txt")

Esto ya no devolverá nulo, pero devolverá su clase. Espero que esto ayude a alguien. Me resulta extraño que la "resources"carpeta no se copie también, sino solo las subcarpetas y los archivos directamente en la "resources"carpeta. Me parece lógico que la "resources"carpeta también se encuentre en"myapp/target/classes"

Johnny
fuente
1
En mi target/classes, solo puedo ver archivos en los recursos principales y no probar los recursos. ¿Por qué?
Ava
@Ava Agregue la carpeta de prueba como su carpeta de origen y ¡listo!
Aakash Parashar
@Ava, seguro que es una respuesta tardía para ti, pero puede ayudar a alguien. Debe ejecutar el mvn clean test-compilecomando, como sigue compileen el ciclo de vida de Maven . Eso generará target/test-classes.
Alexander Radchenko
34

Con la esperanza de proporcionar información adicional para aquellos que no captan esto tan rápido como los demás, me gustaría proporcionar mi escenario, ya que tiene una configuración ligeramente diferente. Mi proyecto se configuró con la siguiente estructura de directorios (usando Eclipse):

Proyecto/
  src / // código fuente de la aplicación
    org /
      mi proyecto/
        MyClass.java
  prueba / // pruebas unitarias
  res / // recursos
    images / // imágenes PNG para iconos
      my-image.png
    xml / // Archivos XSD para validar archivos XML con JAXB
      mi-esquema.xsd
    conf / // archivo .conf predeterminado para Log4j
      log4j.conf
  lib / // bibliotecas agregadas a la ruta de compilación a través de la configuración del proyecto

Tenía problemas para cargar mis recursos desde el directorio res . Quería que todos mis recursos estuvieran separados de mi código fuente (simplemente para fines de gestión / organización). Entonces, lo que tuve que hacer fue agregar el directorio res a la ruta de compilación y luego acceder al recurso a través de:

static final ClassLoader loader = MyClass.class.getClassLoader();

// in some function
loader.getResource("images/my-image.png");
loader.getResource("xml/my-schema.xsd");
loader.getResource("conf/log4j.conf");

NOTA: Se /omite desde el principio de la cadena de recursos porque estoy usando ClassLoader.getResource (String) en lugar de Class.getResource (String) .

E-rico
fuente
1
. + 1 por sugerir ClassLoader
pyb
1
¡La mejor respuesta sobre este tema! ¡El consejo sobre no usar /al comienzo de una ruta de recursos fue clave!
Kayhadrin
10

Cuando usa 'getResource' en una clase, se resuelve una ruta relativa basada en el paquete en el que se encuentra la clase. Cuando usa 'getResource' en un ClassLoader, una ruta relativa se resuelve basándose en la carpeta raíz.

Si usa una ruta absoluta, ambos métodos 'getResource' comenzarán en la carpeta raíz.

nbeyer
fuente
No olvide los efectos de/
Gilberto
@nbeyer ¿Por qué el uso getResourcecon ruta absoluta comienza en la carpeta raíz? ¿No es absoluto el propósito del camino absoluto ?
Atjua
10

@GianCarlo: puede intentar llamar a la propiedad del sistema user.dir que le dará la raíz de su proyecto java y luego agregar esta ruta a su ruta relativa, por ejemplo:

String root = System.getProperty("user.dir");
String filepath = "/path/to/yourfile.txt"; // in case of Windows: "\\path \\to\\yourfile.txt
String abspath = root+filepath;



// using above path read your file into byte []
File file = new File(abspath);
FileInputStream fis = new FileInputStream(file);
byte []filebytes = new byte[(int)file.length()];
fis.read(filebytes);
Vikram
fuente
1
OP quería ubicar un recurso en la ruta de clases (probablemente en un jar generado durante la compilación). Este método no proporciona una forma de lograr ese objetivo: no puede apuntar Filea un recurso dentro de un archivo jar, solo a una entrada adecuada en el sistema de archivos (por ejemplo, el jar en sí).
Attila
Me gusta la idea de obtener "user.dir" para ver la ruta deseada. Gracias
YouAreAwesome
5

Para aquellos que usan eclipse + maven. Digamos que intenta acceder al archivo images/pic.jpgen formato src/main/resources. Haciéndolo de esta manera:

ClassLoader loader = MyClass.class.getClassLoader();
File file = new File(loader.getResource("images/pic.jpg").getFile());

es perfectamente correcto, pero puede resultar en una excepción de puntero nulo. Parece que eclipse no reconoce las carpetas en la estructura de directorios de maven como carpetas de origen de inmediato. Al eliminar y la src/main/resourcescarpeta de la lista de carpetas de origen del proyecto y volver a colocarla (proyecto> propiedades> ruta de compilación java> fuente> eliminar / agregar carpeta), pude resolver esto.

Paul Mira
fuente
2
resourcesloader.class.getClass()

Se puede dividir en:

Class<resourcesloader> clazz = resourceloader.class;
Class<Class> classClass = clazz.getClass();

Lo que significa que está intentando cargar el recurso utilizando una clase de arranque.

En su lugar, probablemente quieras algo como:

resourcesloader.class.getResource("repository/SSL-Key/cert.jks").toString()

Si solo javac advirtiera sobre la llamada a métodos estáticos en contextos no estáticos ...

Tom Hawtin - tackline
fuente
1

¿Realiza el siguiente trabajo?

resourcesloader.class.getClass().getResource("/package1/resources/repository/SSL-Key/cert.jks")

¿Hay alguna razón por la que no pueda especificar la ruta completa, incluido el paquete?

RichH
fuente
1

Siguiendo las dos respuestas mencionadas anteriormente. El primero

resourcesloader.class.getClassLoader().getResource("package1/resources/repository/SSL-Key/cert.jks").toString();
resourcesloader.class.getResource("repository/SSL-Key/cert.jks").toString()

¿Debería ser una y la misma cosa?

manocha_ak
fuente
1

Para obtener una ruta real al archivo, puede intentar esto:

URL fileUrl = Resourceloader.class.getResource("resources/repository/SSL-Key/cert.jks");
String pathToClass = fileUrl.getPath;    

Resourceloader es el nombre de clase aquí. "resources / repository / SSL-Key / cert.jks" es la ruta relativa al archivo. Si tuvieras tu guiclass en ./package1/java con el resto de la estructura de carpetas restante, tomarías "../resources/repository/SSL-Key/cert.jks" como ruta relativa debido a las reglas que definen la ruta relativa.

De esta forma puede leer su archivo con BufferedReader. NO USE LA CADENA para identificar la ruta al archivo, porque si tiene espacios o algunos caracteres del alfabeto no inglés en su ruta, tendrá problemas y no se encontrará el archivo.

BufferedReader bufferedReader = new BufferedReader(
                        new InputStreamReader(fileUrl.openStream()));
Nikto
fuente
0

Hice una pequeña modificación en el trazador de líneas de @ jonathan.cone (agregando .getFile()) para evitar la excepción de puntero nulo y estableciendo la ruta al directorio de datos. Esto es lo que funcionó para mí:

String realmID = new java.util.Scanner(new java.io.File(RandomDataGenerator.class.getClassLoader().getResource("data/aa-qa-id.csv").getFile().toString())).next();
Alferd Nobel
fuente
0

Utilizar esta:

resourcesloader.class.getClassLoader().getResource("/path/to/file").**getPath();**
Oleg Poltoratskii
fuente