2009-07-27 13 views
3

j'ai été confronté avec le code qui essaie de lire des fichiers de configuration à partir du même répertoire dans lequel le fichier .class pour la classe elle-même est:Obtenir le chemin vers le répertoire d'un fichier de classe donnée

File[] configFiles = new File(
    this.getClass().getResource(".").getPath()).listFiles(new FilenameFilter() { 
     public boolean accept(File dir, String name) { 
      return name.endsWith(".xml"); 
     } 
}); 

Apparemment, ce fonctionne dans certains cas (lors de l'exécution du code dans Resin, peut-être), mais pour moi, en cours d'exécution Tomcat, il échoue simplement avec NPE, car getClass().getResource(".") renvoie null. Un collègue a suggéré de créer un autre fichier de configuration contenant une liste de tous les fichiers de configuration ".xml" (ce qui fonctionnerait bien ici car il reste assez statique), et que vous ne devriez pas vraiment essayer de faire quelque chose comme ça dans Java.

Encore, je me demande s'il y a une certaine manière de manière sympa, qui fonctionne universellement, pour obtenir le chemin d'accès au répertoire où se trouve un fichier .class donné? Je suppose que vous pourriez l'obtenir à partir du chemin du fichier .class se présente comme suit:

new File(this.getClass().getResource("MyClass.class").getPath()).getParent() 

... mais est-ce la seule/manière la plus propre?

Modifier: Pour clarifier, supposons que nous savons ceci est utilisé dans une application déployée de telle sorte que MyClass.class sera toujours lu à partir d'un fichier .class sur le disque et les ressources seront là en ce même répertoire.

+0

cette question connexe trouvé: http://stackoverflow.com/questions/778187/getting-directory-path-to-class-file-containing-main Sa réponse acceptée utilise essentiellement ce que je suggérais [getResource ("MyClass.class"). GetPath()] ... mais il ne répond pas directement si c'est le seul ou le meilleur moyen. – Jonik

Répondre

2

Qu'est-ce qui vous fait supposer qu'il existe un fichier de classe sur le disque dans son propre répertoire?

Une classe pourrait être:

  • Créé entièrement en mémoire
  • Chargé d'une connexion réseau
  • chargé d'un fichier jar

Vous pouvez obtenir l'URL utilisée pour créer la classe elle-même, et si cela commence par file:// alors vous pourriez obtenir le reste ... mais cela ne fonctionnera pas pour toutes les classes.

+0

Oui, je pense que c'est à peu près ce que mon collègue voulait dire en proposant l'alternative ... Mais il y a * scénarios * quand on sait que la classe sera toujours chargée à partir d'un fichier sur disque - donc si c'est le cas, ce que j'ai suggéré dans la question la manière la plus propre? Merci pour le conseil sur la vérification du début de l'URL! – Jonik

+0

Oui, ce que vous avez là regarde de la manière la plus propre à moi si vous ajoutez une vérification du protocole de fichier. –

2

Si la ressource se trouve dans le même dossier qu'un fichier .class, elle doit être accessible via le chemin de classe et peut être chargée via getResourceAsStream directement.

this.getClass().getResourceAsStream("filename.xml") 

Comme posté plus tôt, les cours eux-mêmes peuvent être chargées à distance ou dans des endroits où il n'y a pas un bon « chemin » (par exemple à partir d'un jarfile)

+1

Oui, bien sûr; Je cherchais la façon la plus simple d'obtenir le chemin * directory * (parce que nous lisons plusieurs fichiers de ressources à partir de là) – Jonik

+0

Ah essayez-vous de lire tout, par ex. ".xml" fichiers du chemin de la classe à ce stade, sans avoir à connaître leurs noms à l'avance? –

+1

Oui, c'était principalement le point. (Bien que dans ce cas, nous connaissons essentiellement les noms, je voudrais juste lire les fichiers dynamiquement, pour éviter de les énumérer quelque part ou quelque chose comme ça.) – Jonik

1

Je suis d'accord avec votre collègue que le chargement de classe Java n'a pas été conçu pour gérer ce cas d'utilisation. Sun Facelets utilise une stratégie similaire consistant à supposer que les URL peuvent être mappées sur des fichiers, et ce n'est pas joli. Je suis d'accord avec le commentaire de Jon que votre solution getResource est probablement la plus propre étant donné vos hypothèses de déploiement. Puisque vous avez demandé si c'était le seul moyen, je proposerai aussi getClass(). GetProtectionDomain(). GetCodeSource(). GetLocation(), qui devrait être l'URL que le chargeur de classe a réellement chargé votre classe (vous auriez besoin de ajouter les sous-répertoires pour le paquet de votre classe). Cette stratégie a également les mêmes hypothèses d'URL vers fichier, donc ce n'est pas mieux à cet égard. Je ne peux penser à aucune autre solution générale.

Notez que getResource renvoie une URL codée, ce qui signifie que vous ne devez pas utiliser getPath() directement.En particulier, les espaces provoqueront des problèmes, bien que cela ne soit pas un problème si vous contrôlez votre environnement. Envisagez d'utiliser un nouveau fichier (URL.toURI()).

0

Je pense que vous pouvez être intéressé par PathMatchingResourcePatternResolver de Spring Framework. Vous pouvez l'utiliser directement dans votre code pour naviguer dans les fichiers de configuration ou vous pouvez rechercher l'implémentation here.

3

Je sais que ce fil de discussion est ancien, mais c'est le meilleur résultat dans les recherches Google, et il n'y avait pas de réponses satisfaisantes ici, pour moi. Voici un code que j'ai écrit, qui fonctionne très bien pour moi. Bien sûr, il est à noter qu'il n'a peut-être pas été chargé à partir du disque, mais il en tient compte et renvoie null dans ce cas. Cela fonctionne très bien pour trouver le "conteneur", c'est-à-dire l'emplacement racine d'une classe, que ce soit un pot ou un dossier. Cela peut ne pas convenir à vos besoins directement. Sinon, n'hésitez pas à déchirer les parties du code dont vous avez besoin.

/** 
* Returns the container url for this class. This varies based on whether or 
* not the class files are in a zip/jar or not, so this method standardizes 
* that. The method may return null, if the class is a dynamically generated 
* class (perhaps with asm, or a proxy class) 
* 
* @param c The class to find the container for 
* @return 
*/ 
public static String GetClassContainer(Class c) { 
    if (c == null) { 
     throw new NullPointerException("The Class passed to this method may not be null"); 
    } 
    try { 
     while(c.isMemberClass() || c.isAnonymousClass()){ 
      c = c.getEnclosingClass(); //Get the actual enclosing file 
     } 
     if (c.getProtectionDomain().getCodeSource() == null) { 
      //This is a proxy or other dynamically generated class, and has no physical container, 
      //so just return null. 
      return null; 
     } 
     String packageRoot; 
     try { 
      //This is the full path to THIS file, but we need to get the package root. 
      String thisClass = c.getResource(c.getSimpleName() + ".class").toString(); 
      packageRoot = StringUtils.replaceLast(thisClass, Pattern.quote(c.getName().replaceAll("\\.", "/") + ".class"), ""); 
      if(packageRoot.endsWith("!/")){ 
       packageRoot = StringUtils.replaceLast(packageRoot, "!/", ""); 
      } 
     } catch (Exception e) { 
      //Hmm, ok, try this then 
      packageRoot = c.getProtectionDomain().getCodeSource().getLocation().toString(); 
     } 
     packageRoot = URLDecoder.decode(packageRoot, "UTF-8"); 
     return packageRoot; 
    } catch (Exception e) { 
     throw new RuntimeException("While interrogating " + c.getName() + ", an unexpected exception was thrown.", e); 
    } 
} 
Questions connexes