Ressource Java sous forme de fichier


122

Existe-t-il un moyen en Java de construire une instance de fichier sur une ressource récupérée à partir d'un fichier jar via le chargeur de classe?

Mon application utilise certains fichiers du jar (par défaut) ou d'un répertoire de système de fichiers spécifié lors de l'exécution (entrée utilisateur). Je recherche un moyen cohérent de
a) charger ces fichiers en tant que flux
b) lister les fichiers dans le répertoire défini par l'utilisateur ou dans le répertoire dans le jar respectivement

Edit: Apparemment, l'approche idéale serait de rester à l'écart de java.io.File. Existe-t-il un moyen de charger un répertoire à partir du chemin de classe et de répertorier son contenu (fichiers / entités qu'il contient)?

Réponses:


58

ClassLoader.getResourceAsStreamet Class.getResourceAsStreamsont certainement la voie à suivre pour charger les données de ressources. Cependant, je ne crois pas qu'il existe un moyen de "lister" le contenu d'un élément du classpath.

Dans certains cas, cela peut être tout simplement impossible - par exemple, a ClassLoader pourrait générer des données à la volée, en fonction du nom de ressource demandé. Si vous regardez l' ClassLoaderAPI (qui est essentiellement ce que fonctionne le mécanisme de chemin de classe), vous verrez qu'il n'y a rien pour faire ce que vous voulez.

Si vous savez que vous avez réellement un fichier jar, vous pouvez le charger avec ZipInputStream pour savoir ce qui est disponible. Cela signifie que vous aurez un code différent pour les répertoires et les fichiers jar.

Une alternative, si les fichiers sont d'abord créés séparément, consiste à inclure une sorte de fichier manifeste contenant la liste des ressources disponibles. Regroupez-le dans le fichier jar ou incluez-le dans le système de fichiers en tant que fichier et chargez-le avant d'offrir à l'utilisateur un choix de ressources.


3
Je suis d'accord que c'est ennuyeux - mais cela rend ClassLoader plus largement applicable par d'autres moyens. Par exemple, il est facile d'écrire un "chargeur de classe Web" parce que le Web est bon pour récupérer des fichiers, mais il ne répertorie généralement pas les fichiers.
Jon Skeet

Il semble que si la ressource que vous essayez de charger est beaucoup plus grande que 1 Mo, InputStreamvous obtenez des getResourceAsStreamarrêts pour récupérer les octets de la ressource après cette taille et retourne à la place 0 ssi elle est contenue dans un système de fichiers compressé comme un fichier jar. Vous semblez être obligé d'utiliser getResourceet de charger le fichier indépendamment de cela dans ce cas.
mgttlinger

1
@mgttlinger: Cela me semble peu probable ... ça vaut probablement la peine de poster une nouvelle question avec une repro si vous le pouvez.
Jon Skeet du

Le problème était dû à la readméthode déterminant la quantité de données à lire (je n'étais pas au courant de cela). Et il semble que tout le fichier soit lu si le fichier en cours de lecture se trouve dans un dossier normal. Si le fichier se trouve dans un bocal parce qu'il a été empaqueté, il n'en lit que des parties.
mgttlinger

1
@mgttlinger: Non, il ne lira pas que des parties de celui-ci - mais il pourrait ne pas remplir tout le tampon fourni à chaque appel de lecture. Comme toujours avec InputStream, si vous voulez lire toute la ressource, vous devez boucler jusqu'à ce que readrenvoie -1.
Jon Skeet

98

J'ai eu le même problème et j'ai pu utiliser ce qui suit:

// Load the directory as a resource
URL dir_url = ClassLoader.getSystemResource(dir_path);
// Turn the resource into a File object
File dir = new File(dir_url.toURI());
// List the directory
String files = dir.list()

45
Cette approche ne fonctionne pas avec les JAR dans le
chemin de classe

1
@ yegor256 Si votre fichier est dans un bocal, vous pouvez créer un FileSystemobjet et en obtenir le Path. Ensuite, vous pouvez le lire comme d'habitude. (voir stackoverflow.com/a/22605905/1876344 )
mgttlinger

53

Voici un peu de code d'une de mes applications ... Faites-moi savoir si cela répond à vos besoins. Vous pouvez l'utiliser si vous connaissez le fichier que vous souhaitez utiliser.

URL defaultImage = ClassA.class.getResource("/packageA/subPackage/image-name.png");
File imageFile = new File(defaultImage.toURI());

J'espère que cela pourra aider.


Oui, mais toURI()échouera.
Olivier Faucheux

10

Un moyen fiable de construire une instance de fichier sur une ressource récupérée à partir d'un fichier jar est de copier la ressource en tant que flux dans un fichier temporaire (le fichier temporaire sera supprimé lorsque la JVM se fermera):

public static File getResourceAsFile(String resourcePath) {
    try {
        InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(resourcePath);
        if (in == null) {
            return null;
        }

        File tempFile = File.createTempFile(String.valueOf(in.hashCode()), ".tmp");
        tempFile.deleteOnExit();

        try (FileOutputStream out = new FileOutputStream(tempFile)) {
            //copy stream
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
            }
        }
        return tempFile;
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
}

4

Essaye ça:

ClassLoader.getResourceAsStream ("some/pkg/resource.properties");

Il existe d'autres méthodes disponibles, par exemple, voir ici: http://www.javaworld.com/javaworld/javaqa/2003-08/01-qa-0808-property.html


Merci pour votre réponse. Je connais getResourceAsStream, mais je ne pense pas que je puisse charger un répertoire à partir du chemin de classe à travers cela.
Mantrum

Dans le répertoire Java se trouve un fichier (racines UNIX je suppose) donc vous devriez au moins essayer.
topchef

Je pense que pour lister les fichiers dans un répertoire, vous devrez utiliser java.io.File. Vous pouvez rechercher des fichiers avec le ClassLoader.findResource qui renvoie une URL qui peut être transmise à File.
Nathan Voxland

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.