java.de nio.archivo.Camino por una ruta de clases de recursos

Hay una API para obtener una ruta de clases de recursos (por ejemplo, lo que me gustaría obtener de de la Clase.getResource(Cadena)) como un java.nio.file.Path? Idealmente, me gustaría utilizar la fantasía Ruta nueva Api con la ruta de clases de recursos.

  • Así, tomar el largo camino (juego de palabras), usted tiene Paths.get(URI), a continuación de la URL.gira(), and last getResource () » que devuelve un URL. Usted podría ser capaz de cadena esos juntos. He probado aunque.

8 Kommentare

  1. 149

    Este me funciona:

    return Paths.get(ClassLoader.getSystemResource(resourceName).toURI());
    • Esto no funcionará con recursos .los archivos jar.
    • si los recursos .archivo jar podría intentar este Recurso de los recursos = new ClassPathResource(«usage.txt»); clases bufferedreader lector = new clases bufferedreader(new InputStreamReader(recurso.getInputStream()));` por favor, consulte stackoverflow.com/questions/25869428/…
    • que una Primavera enfoque específico. No funciona en absoluto cuando la Primavera no está siendo utilizado.
    • Si su aplicación no se basa en el sistema del cargador de clases, debe ser Thread.currentThread().getContextClassLoader().getResource(resourceName).toURI()
  2. 26

    Adivinar que lo que quieres hacer, es llamar a los Archivos.líneas(…) en un recurso que viene de la ruta de clases – posiblemente desde dentro de un frasco.

    Desde Oracle complicado de la noción de cuando un Camino es un Camino por no hacer getResource devolver un utilizable camino si reside en un archivo jar, lo que usted necesita hacer es algo como esto:

    Stream<String> stream = new BufferedReader(new InputStreamReader(ClassLoader.getSystemResourceAsStream("/filename.txt"))).lines();
    • si el anterior «/» es necesario en tu caso no sé, pero en mi caso class.getResource requiere una barra pero getSystemResourceAsStream no puede encontrar el archivo cuando el prefijo con una barra diagonal.
  3. 9

    La mayoría de la solución general es como sigue:

    interface IOConsumer<T> {
        void accept(T t) throws IOException;
    }
    public static void processRessource(URI uri, IOConsumer<Path> action) throws IOException {
        try {
            Path p=Paths.get(uri);
            action.accept(p);
        }
        catch(FileSystemNotFoundException ex) {
            try(FileSystem fs = FileSystems.newFileSystem(
                    uri, Collections.<String,Object>emptyMap())) {
                Path p = fs.provider().getPath(uri);
                action.accept(p);
            }
        }
    }

    El principal obstáculo es lidiar con las dos posibilidades, ya sea, tener un sistema de archivos existente que debemos utilizar, pero no cerca (como con file URIs o Java 9 del módulo de almacenamiento), o tener que abrir y así cerrar de forma segura el sistema de ficheros de nosotros mismos (como zip/jar archivos).

    Por lo tanto, la solución por encima de los encapsula la acción real en un interface, maneja ambos casos, de forma segura cierre luego en el segundo caso, y funciona a partir de Java de 7 a Java 10. Pregunta si ya hay abierto un sistema de ficheros antes de la apertura de uno nuevo, por lo que también funciona en el caso de que otro componente de su aplicación ya ha abierto un sistema de ficheros para el mismo zip/jar archivo.

    Puede ser utilizado en todas las versiones de Java llamada anteriormente, por ejemplo, para listar el contenido de un paquete (java.lang en el ejemplo) como Paths, como este:

    processRessource(Object.class.getResource("Object.class").toURI(), new IOConsumer<Path>() {
        public void accept(Path path) throws IOException {
            try(DirectoryStream<Path> ds = Files.newDirectoryStream(path.getParent())) {
                for(Path p: ds)
                    System.out.println(p);
            }
        }
    });

    Con Java 8 o posterior, puede utilizar expresiones lambda o método de referencias para representar la acción en sí, por ejemplo,

    processRessource(Object.class.getResource("Object.class").toURI(), path -> {
        try(Stream<Path> stream = Files.list(path.getParent())) {
            stream.forEach(System.out::println);
        }
    });

    a hacer lo mismo.


    La última versión de Java 9 módulo del sistema se ha roto el anterior ejemplo de código. El JRE de forma incoherente devuelve la ruta de acceso /java.base/java/lang/Object.class para Object.class.getResource("Object.class") mientras que debería ser /modules/java.base/java/lang/Object.class. Esto puede ser solucionado por anteponiendo la falta /modules/ cuando la ruta de acceso principal es reportado como inexistente:

    processRessource(Object.class.getResource("Object.class").toURI(), path -> {
        Path p = path.getParent();
        if(!Files.exists(p))
            p = p.resolve("/modules").resolve(p.getRoot().relativize(p));
        try(Stream<Path> stream = Files.list(p)) {
            stream.forEach(System.out::println);
        }
    });

    A continuación, volverá a trabajar con todas las versiones y métodos de almacenamiento.

  4. 9

    Resulta que usted puede hacer esto, con la ayuda de la incorporada en el Proveedor de Sistema de Archivos Zip. Sin embargo, el paso de un recurso de URI directamente a Paths.get no funciona; en su lugar, uno debe primero crear un sistema de archivos zip para que el frasco URI sin el nombre de la entrada, a continuación, consulte la entrada en ese sistema de ficheros:

    static Path resourceToPath(URL resource)
    throws IOException,
           URISyntaxException {
    
        Objects.requireNonNull(resource, "Resource URL cannot be null");
        URI uri = resource.toURI();
    
        String scheme = uri.getScheme();
        if (scheme.equals("file")) {
            return Paths.get(uri);
        }
    
        if (!scheme.equals("jar")) {
            throw new IllegalArgumentException("Cannot convert to Path: " + uri);
        }
    
        String s = uri.toString();
        int separator = s.indexOf("!/");
        String entryName = s.substring(separator + 2);
        URI fileURI = URI.create(s.substring(0, separator));
    
        FileSystem fs = FileSystems.newFileSystem(fileURI,
            Collections.<String, Object>emptyMap());
        return fs.getPath(entryName);
    }

    Actualización:

    Se ha señalado acertadamente que el código de arriba contiene una pérdida de recursos, ya que el código se abre un nuevo objeto del sistema de archivos, pero nunca se cierra. El mejor enfoque es el de pasar de un Consumidor-como objeto trabajador, de manera parecida a como Holger la respuesta de ella. Abra el ZipFS sistema de archivos sólo el tiempo suficiente para que el trabajador a hacer lo que se debe hacer con la Ruta de acceso (siempre y cuando el trabajador no intenta almacenar el objeto de Trazado para uso posterior), a continuación, cierre el sistema de Ficheros.

    • Tenga cuidado al recién creado fs. Una segunda llamada con el mismo bote se va a lanzar una excepción a quejarse de una ya existente sistema de ficheros. Será mejor que trate de hacer(el sistema de archivos fs=…){return fs.getPath(entryName);} o si quieres tener esta caché hacer más avanzadas de manejo. En la forma actual, es arriesgado.
    • Además de la cuestión de la potencialmente no cerrado nuevo sistema de ficheros, los supuestos acerca de la relación entre los esquemas y la necesidad de la apertura de un nuevo sistema de ficheros y el desconcierto con el URI del contenido límite de la utilidad de la solución. He configurado un respuesta, que muestra un enfoque general que simplifica la operación y asas de nuevos esquemas como el nuevo Java 9 almacenamiento de clase al mismo tiempo. También funciona cuando alguien dentro de la aplicación ya ha abierto el sistema de ficheros (o se llama al método dos veces por el mismo frasco)…
    • Dependiendo del uso de esta solución, no cerrado newFileSystem puede conducir a múltiples recursos colgando alrededor de abrir para siempre. Aunque @raisercostin anexo evita el error al intentar crear un mundo ya creado el sistema de archivos, si intenta utilizar la devuelve Path obtendrá un ClosedFileSystemException. @Holger respuesta funciona bien para mí.
  5. 5

    Escribí un pequeño método auxiliar para leer Paths de su clase de recursos. Es muy práctico de usar, ya que sólo necesita una referencia de la clase que usted ha almacenado sus recursos, así como el nombre del propio recurso.

    public static Path getResourcePath(Class<?> resourceClass, String resourceName) throws URISyntaxException {
        URL url = resourceClass.getResource(resourceName);
        return Paths.get(url.toURI());
    }  
  6. 1

    Usted no puede crear la URI de los recursos dentro del archivo jar. Usted puede simplemente escribir en el archivo temporal y, a continuación, utilizarlo (java8):

    Path path = File.createTempFile("some", "address").toPath();
    Files.copy(ClassLoader.getSystemResourceAsStream("/path/to/resource"), path, StandardCopyOption.REPLACE_EXISTING);
  7. 1

    Leer un Archivo desde la carpeta de recursos para el uso de NIO, en java8

    public static String read(String fileName) {
    
            Path path;
            StringBuilder data = new StringBuilder();
            Stream<String> lines = null;
            try {
                path = Paths.get(Thread.currentThread().getContextClassLoader().getResource(fileName).toURI());
                lines = Files.lines(path);
            } catch (URISyntaxException | IOException e) {
                logger.error("Error in reading propertied file " + e);
                throw new RuntimeException(e);
            }
    
            lines.forEach(line -> data.append(line));
            lines.close();
            return data.toString();
        }

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea