Utilitaires pour lire le fichier texte de ressource sur String (Java) [fermé]
215
Existe-t-il un utilitaire qui aide à lire un fichier texte dans la ressource dans une chaîne. Je suppose que c'est une exigence populaire, mais je n'ai trouvé aucun utilitaire après Google.
veuillez clarifier ce que vous entendez par «fichier texte de ressource» par rapport à «fichier texte de ressource» - il n'est pas facile de comprendre ce que vous essayez de réaliser.
Mat
C'est juste un fichier texte sous classpath comme "classpath *: mytext / text.txt"
Loc Phan
Réponses:
301
Oui, Guava fournit cela en Resourcesclasse. Par exemple:
URL url =Resources.getResource("foo.txt");String text =Resources.toString(url,StandardCharsets.UTF_8);
@JonSkeet C'est très bien, mais pour les applications web ce n'est peut-être pas la meilleure solution, l'implémentation de getResourceutilise Resource.class.getClassLoadermais dans les applications web, ce n'est peut-être pas "votre" chargeur de classe, il est donc recommandé (par exemple dans [1]) d'utiliser Thread.currentThread().getContextClassLoader().getResourceAsStreamà la place (référence [1]: stackoverflow.com/questions/676250/… )
Eran Medan
2
@EranMedan: Oui, si vous voulez le chargeur de classe de contexte, vous voudriez l'utiliser explicitement.
Jon Skeet
6
Dans le cas particulier où la ressource est à côté de votre classe, vous pouvez faire Resources.toString(MyClass.getResource("foo.txt"), Charsets.UTF_8)ce qui garantit l'utilisation du chargeur de classe correct.
Bogdan Calmac
2
com.google.common.io.Resourcesest marqué comme instable selon SonarQube
Ghilteras
1
guavaa changé la mise en œuvre. Pour la goyave 23, l'implémentation aime suivre. ClassLoader loader = MoreObjects.firstNonNull( Thread.currentThread().getContextClassLoader(), Resources.class.getClassLoader());
xxy
172
Vous pouvez utiliser l'ancien onliner de Stupid Scanner pour le faire sans aucune dépendance supplémentaire comme la goyave:
String text =newScanner(AppropriateClass.class.getResourceAsStream("foo.txt"),"UTF-8").useDelimiter("\\A").next();
Les gars, n'utilisez pas de trucs tiers sauf si vous en avez vraiment besoin. Il y a déjà beaucoup de fonctionnalités dans le JDK.
Éviter les tiers est un principe raisonnable. Malheureusement, la bibliothèque principale semble allergique à la modélisation de cas d'utilisation réels. Regardez les fichiers de Java 7 et dites-moi pourquoi tout lire à partir d'une ressource classpath n'y était pas inclus? Ou au moins en utilisant un «système de fichiers» standardisé.
Dilum Ranatunga
3
Est-il - ou n'est-il pas - également nécessaire de fermer le flux? La goyave ferme le flux en interne.
virgo47
A fonctionné magnifiquement pour moi aussi! Je suis également d'accord sur la chose tierce: dans de nombreuses réponses, la réponse par défaut semble toujours être d'utiliser une bibliothèque tierce - que ce soit d'Apache ou de quelqu'un d'autre.
Terje Dahl
1
changer CartApplication.class.getResourceAsStreampour CartApplication.class.getClassLoader().getResourceAsStreamcharger les ressources dans le pot actuel .. comme srm / test / resources
Chris DaMour
5
Bien que j'aie utilisé cela, je ne suis absolument pas d'accord pour éviter les packages tiers. Le fait qu'en Java, la seule façon de lire facilement un fichier en chaîne est avec l'astuce du scanner est assez triste. L'alternative à l'utilisation d'une bibliothèque tierce est que tout le monde créera simplement ses propres wrappers. La goyave pour IO gagne haut la main si vous avez beaucoup de besoins pour ce type d'opération. Là où je serai d'accord, c'est que vous ne devez pas importer un paquet tiers si vous n'avez qu'un seul endroit dans votre code où vous voulez le faire. Ce serait exo imo.
Expliquez s'il vous plaît pourquoi cela fonctionne, pourquoi il est meilleur que d'autres alternatives et toutes les considérations de performances / d'encodage nécessaires.
nanofarad
5
C'est nio 2 dans java 1.7. C'est la fermeture native de Java. Pour l'encodage, utilisez une nouvelle chaîne (octets, StandardCharsets.UTF_8)
Kovalsky Dmitryi
5
dans mon cas j'avais besoin getClass().getClassLoader()mais sinon super solution!
Emmanuel Touzery
3
Cela ne fonctionnera pas, une fois l'application emballée dans un bocal.
Daniel Bo
65
Solution Java 8+ pure et simple, compatible avec les pots
Cette méthode simple ci-dessous fera très bien l'affaire si vous utilisez Java 8 ou supérieur:
/**
* Reads given resource file as a string.
*
* @param fileName path to the resource file
* @return the file's contents
* @throws IOException if read fails for any reason
*/staticString getResourceFileAsString(String fileName)throwsIOException{ClassLoader classLoader =ClassLoader.getSystemClassLoader();try(InputStream is = classLoader.getResourceAsStream(fileName)){if(is ==null)returnnull;try(InputStreamReader isr =newInputStreamReader(is);BufferedReader reader =newBufferedReader(isr)){return reader.lines().collect(Collectors.joining(System.lineSeparator()));}}}
Et cela fonctionne également avec des ressources dans des fichiers jar .
À propos de l'encodage de texte: InputStreamReaderutilisera le jeu de caractères système par défaut au cas où vous n'en spécifieriez pas un. Vous voudrez peut-être le spécifier vous-même pour éviter les problèmes de décodage, comme ceci:
newInputStreamReader(isr,StandardCharsets.UTF_8);
Évitez les dépendances inutiles
Préférez toujours ne pas dépendre de grosses bibliothèques grasses. À moins que vous n'utilisiez déjà Guava ou Apache Commons IO pour d'autres tâches, ajouter ces bibliothèques à votre projet juste pour pouvoir lire à partir d'un fichier semble un peu trop.
Méthode "simple"? Tu dois te moquer de moi
Je comprends que Java pur ne fait pas du bon travail quand il s'agit de faire des tâches simples comme celle-ci. Par exemple, voici comment nous lisons à partir d'un fichier dans Node.js:
Simple et facile à lire (bien que les gens aiment toujours compter sur de nombreuses dépendances de toute façon, principalement en raison de l'ignorance). Ou en Python:
with open('some-file.txt','r')as f:
content = f.read()
C'est triste, mais c'est toujours simple pour les normes Java et tout ce que vous avez à faire est de copier la méthode ci-dessus dans votre projet et de l'utiliser. Je ne vous demande même pas de comprendre ce qui se passe là-dedans, car cela n'a vraiment d'importance pour personne. Cela fonctionne, point :-)
@zakmck, essayez de garder vos commentaires constructifs. En grandissant en tant que développeur mature, vous apprenez que vous voulez parfois «réinventer la roue». Par exemple, vous devrez peut-être garder votre binaire en dessous de la taille du seuil. Les bibliothèques font souvent augmenter la taille de votre application par ordre de grandeur. On pourrait argumenter tout le contraire de ce que vous avez dit: "Pas besoin d'écrire du code. Oui, importons simplement les bibliothèques à chaque fois". Préféreriez-vous vraiment importer une bibliothèque juste pour vous faire économiser 3 lignes de code? Je parie que l'ajout de la bibliothèque augmentera votre LOC de plus que cela. La clé est l'équilibre.
Lucio Paiva
3
Eh bien, tout le monde ne fait pas tourner des trucs sur le cloud. Il existe des systèmes embarqués partout qui exécutent Java, par exemple. Je ne vois tout simplement pas votre intérêt à critiquer les réponses qui fournissent des approches totalement valables, étant donné que vous vous dites que vous allez accepter la suggestion d'utiliser JDK directement dans votre propre code. Quoi qu'il en soit, essayons de garder les commentaires strictement pour aider à améliorer les réponses, pas pour discuter des opinions.
Lucio Paiva
1
Bonne solution JDK uniquement. J'ajouterais seulement vérifier si la InputStreamvariable isest nullou non.
scrutari
2
Agréable. J'ai utilisé ça. Vous pouvez également envisager de fermer les flux / lecteurs.
dimplex
1
@RobertBain J'ai modifié la réponse pour ajouter des informations sur l'avertissement de jeu de caractères. Faites-moi savoir si vous découvrez ce qui n'a pas fonctionné avec le chargeur de classe dans AWS afin que je puisse également l'ajouter à la réponse. Merci!
Lucio Paiva
57
Guava a une méthode "toString" pour lire un fichier dans une chaîne:
Ou si c'est un flux d'entrée, la goyave a aussi un bon moyen pour celaString stringFromStream = CharStreams.toString(new InputStreamReader(resourceAsStream, "UTF-8"));
Je préfère "" à ce cas où cela n'est pas disponible
user833970
11
Tout comme compact, mais avec la fermeture des flux d'entrée: IOUtils.toString(this.getClass().getResource("foo.xml"), "UTF-8").
Bogdan Calmac
1
Si cette solution ne fonctionne pas, essayez d'ajouter getClassLoader()à la chaîne de méthodes: String text = IOUtils.toString( getClass().getClassLoader().getResourceAsStream("foo.xml"), StandardCharsets.UTF_8);
URL url =Resources.getResource("myFile.txt");File myFile =newFile(url.toURI());String content =FileUtils.readFileToString(myFile,"UTF-8");// or any other encoding
Pourquoi faut-il spécifier l'encodage, je ne comprends pas. Si je lis le fichier, je veux juste ce qu'il contient, il devrait comprendre à quoi sert l'encodage comme le fait mon éditeur. Lorsque j'ouvre dans le Bloc-notes ou ++, je ne lui dis pas quel encodage il doit utiliser. J'utilise cette méthode et ensuite writeStringToFile ... mais le contenu diffère. J'obtiens des jetons étranges dans le fichier cloné. Je ne comprends pas pourquoi je devrais spécifier un encodage.
mmm
11
@Hamidan, choisir le bon encodage est un algorithme très complexe. Il est souvent implémenté dans l'éditeur de texte mais ils ne parviennent pas toujours à détecter le codage correct. Je ne m'attendrais pas à ce qu'une API de lecture de fichiers intègre un algorithme aussi complexe pour lire mon fichier.
Vincent Robert
1
@SecretService En outre, ces algorithmes utilisent des informations telles que la langue du système d'exploitation, les paramètres régionaux et d'autres paramètres régionaux, ce qui signifie que la lecture d'un fichier sans spécifier d'encodage peut fonctionner sur votre configuration mais pas sur celle de quelqu'un d'autre.
Je ne pense pas que cela fonctionnera si la ressource se trouve dans un bocal. Ce ne sera alors pas un fichier.
Ville Oikarinen
16
J'ai souvent eu ce problème moi-même. Pour éviter les dépendances sur les petits projets, j'écris souvent une petite fonction utilitaire quand je n'ai pas besoin de communs io ou autres. Voici le code pour charger le contenu du fichier dans un tampon de chaîne:
StringBuffer sb =newStringBuffer();BufferedReader br =newBufferedReader(newInputStreamReader(getClass().getResourceAsStream("path/to/textfile.txt"),"UTF-8"));for(int c = br.read(); c !=-1; c = br.read()) sb.append((char)c);System.out.println(sb.toString());
La spécification de l'encodage est importante dans ce cas, car vous pourriez avoir modifié votre fichier en UTF-8, puis le mettre dans un bocal, et l'ordinateur qui ouvre le fichier peut avoir CP-1251 comme encodage de fichier natif (par exemple) ; dans ce cas, vous ne connaissez jamais le codage cible, par conséquent, les informations de codage explicites sont cruciales. La boucle pour lire le fichier char par char semble également inefficace, mais elle est utilisée sur un BufferedReader, et donc assez rapide.
Quelles instructions d'importation sont nécessaires pour extraire les classes "Files" et "Paths"?
Steve Scherer
1
les deux font partie du package java.nio.file disponible à partir de JDK 7+
Raghu K Nair
Ne fonctionne pas dans un fichier jar.
Displee
4
Si vous souhaitez obtenir votre chaîne à partir d'une ressource de projet comme le fichier testcase / foo.json dans src / main / resources dans votre projet, procédez comme suit:
Le fichier ne fonctionne que pour les ressources de chemin de classe qui sont, enfin, des fichiers. Pas si ce sont des éléments dans un fichier .jar, ou une partie d'un gros pot, l'une des autres implémentations du chargeur de classe.
toolforger
2
J'utilise ce qui suit pour lire les fichiers de ressources à partir de classpath:
package test;import java.io.InputStream;import java.nio.charset.StandardCharsets;import java.util.Scanner;publicclassMain{publicstaticvoid main(String[] args){try{String fileContent = getFileFromResources("resourcesFile.txt");System.out.println(fileContent);}catch(Exception e){
e.printStackTrace();}}//USE THIS FUNCTION TO READ CONTENT OF A FILE, IT MUST EXIST IN "RESOURCES" FOLDERpublicstaticString getFileFromResources(String fileName)throwsException{ClassLoader classLoader =Main.class.getClassLoader();InputStream stream = classLoader.getResourceAsStream(fileName);String text =null;try(Scanner scanner =newScanner(stream,StandardCharsets.UTF_8.name())){
text = scanner.useDelimiter("\\A").next();}return text;}}
Au moins à partir d'Apache commons-io 2.5, la méthode IOUtils.toString () prend en charge un argument URI et renvoie le contenu des fichiers situés à l'intérieur des jars sur le chemin de classe:
J'aime la réponse d'Akosicki avec le Stupid Scanner Trick. C'est le plus simple que je vois sans dépendances externes qui fonctionne dans Java 8 (et en fait tout le chemin du retour à Java 5). Voici une réponse encore plus simple si vous pouvez utiliser Java 9 ou supérieur (car il a InputStream.readAllBytes()été ajouté à Java 9):
String text =newString(AppropriateClass.class.getResourceAsStream("foo.txt").readAllBytes());
D'où viennent les IOUtils? La source doit être référencée clairement.
ehecatl
0
J'ai écrit des méthodes readResource () ici , pour pouvoir le faire en une seule invocation simple. Cela dépend de la bibliothèque Guava, mais j'aime les méthodes JDK uniquement suggérées dans d'autres réponses et je pense que je vais les changer de cette façon.
publicclassUtils{publicstaticString readResource(String name)throwsURISyntaxException,IOException{
var uri =Utils.class.getResource("/"+ name).toURI();
var path =Paths.get(uri);returnFiles.readString(path);}}
J'aime les utilitaires communs Apache pour ce type de choses et j'utilise ce cas d'utilisation exact (lecture de fichiers depuis classpath) lors des tests, en particulier pour la lecture de fichiers JSON dans /src/test/resourcesle cadre de tests unitaires / d'intégration. par exemple
publicclassFileUtils{publicstaticString getResource(String classpathLocation){try{String message =IOUtils.toString(FileUtils.class.getResourceAsStream(classpathLocation),Charset.defaultCharset());return message;}catch(IOException e){thrownewRuntimeException("Could not read file [ "+ classpathLocation +" ] from classpath", e);}}}
À des fins de test, il peut être agréable d'attraper IOExceptionet de lancer un RuntimeException- votre classe de test pourrait ressembler, par exemple
@Testpublicvoid shouldDoSomething (){String json =FileUtils.getResource("/json/input.json");// Use json as part of test ...}
Réponses:
Oui, Guava fournit cela en
Resources
classe. Par exemple:la source
getResource
utiliseResource.class.getClassLoader
mais dans les applications web, ce n'est peut-être pas "votre" chargeur de classe, il est donc recommandé (par exemple dans [1]) d'utiliserThread.currentThread().getContextClassLoader().getResourceAsStream
à la place (référence [1]: stackoverflow.com/questions/676250/… )Resources.toString(MyClass.getResource("foo.txt"), Charsets.UTF_8)
ce qui garantit l'utilisation du chargeur de classe correct.com.google.common.io.Resources
est marqué comme instable selon SonarQubeguava
a changé la mise en œuvre. Pour la goyave 23, l'implémentation aime suivre.ClassLoader loader = MoreObjects.firstNonNull( Thread.currentThread().getContextClassLoader(), Resources.class.getClassLoader());
Vous pouvez utiliser l'ancien onliner de Stupid Scanner pour le faire sans aucune dépendance supplémentaire comme la goyave:
Les gars, n'utilisez pas de trucs tiers sauf si vous en avez vraiment besoin. Il y a déjà beaucoup de fonctionnalités dans le JDK.
la source
CartApplication.class.getResourceAsStream
pourCartApplication.class.getClassLoader().getResourceAsStream
charger les ressources dans le pot actuel .. comme srm / test / resourcesPour java 7:
la source
getClass().getClassLoader()
mais sinon super solution!Solution Java 8+ pure et simple, compatible avec les pots
Cette méthode simple ci-dessous fera très bien l'affaire si vous utilisez Java 8 ou supérieur:
Et cela fonctionne également avec des ressources dans des fichiers jar .
À propos de l'encodage de texte:
InputStreamReader
utilisera le jeu de caractères système par défaut au cas où vous n'en spécifieriez pas un. Vous voudrez peut-être le spécifier vous-même pour éviter les problèmes de décodage, comme ceci:Évitez les dépendances inutiles
Préférez toujours ne pas dépendre de grosses bibliothèques grasses. À moins que vous n'utilisiez déjà Guava ou Apache Commons IO pour d'autres tâches, ajouter ces bibliothèques à votre projet juste pour pouvoir lire à partir d'un fichier semble un peu trop.
Méthode "simple"? Tu dois te moquer de moi
Je comprends que Java pur ne fait pas du bon travail quand il s'agit de faire des tâches simples comme celle-ci. Par exemple, voici comment nous lisons à partir d'un fichier dans Node.js:
Simple et facile à lire (bien que les gens aiment toujours compter sur de nombreuses dépendances de toute façon, principalement en raison de l'ignorance). Ou en Python:
C'est triste, mais c'est toujours simple pour les normes Java et tout ce que vous avez à faire est de copier la méthode ci-dessus dans votre projet et de l'utiliser. Je ne vous demande même pas de comprendre ce qui se passe là-dedans, car cela n'a vraiment d'importance pour personne. Cela fonctionne, point :-)
la source
InputStream
variableis
estnull
ou non.Guava a une méthode "toString" pour lire un fichier dans une chaîne:
Cette méthode ne nécessite pas que le fichier se trouve dans le chemin de classe (comme dans la réponse précédente de Jon Skeet ).
la source
String stringFromStream = CharStreams.toString(new InputStreamReader(resourceAsStream, "UTF-8"));
yegor256 a trouvé une bonne solution en utilisant Apache Commons IO :
la source
IOUtils.toString(this.getClass().getResource("foo.xml"), "UTF-8")
.getClassLoader()
à la chaîne de méthodes:String text = IOUtils.toString( getClass().getClassLoader().getResourceAsStream("foo.xml"), StandardCharsets.UTF_8);
apache-commons-io a un nom d'utilitaire
FileUtils
:la source
J'ai souvent eu ce problème moi-même. Pour éviter les dépendances sur les petits projets, j'écris souvent une petite fonction utilitaire quand je n'ai pas besoin de communs io ou autres. Voici le code pour charger le contenu du fichier dans un tampon de chaîne:
La spécification de l'encodage est importante dans ce cas, car vous pourriez avoir modifié votre fichier en UTF-8, puis le mettre dans un bocal, et l'ordinateur qui ouvre le fichier peut avoir CP-1251 comme encodage de fichier natif (par exemple) ; dans ce cas, vous ne connaissez jamais le codage cible, par conséquent, les informations de codage explicites sont cruciales. La boucle pour lire le fichier char par char semble également inefficace, mais elle est utilisée sur un BufferedReader, et donc assez rapide.
la source
Vous pouvez utiliser le code suivant Java
la source
Si vous souhaitez obtenir votre chaîne à partir d'une ressource de projet comme le fichier testcase / foo.json dans src / main / resources dans votre projet, procédez comme suit:
Notez que la méthode getClassLoader () est manquante dans certains des autres exemples.
la source
Utilisez FileUtils d'Apache commons. Il a une méthode readFileToString
la source
J'utilise ce qui suit pour lire les fichiers de ressources à partir de
classpath
:Aucune dépendance tierce n'est requise.
la source
Avec un ensemble d'importations statiques, la solution de goyave peut être très compacte:
Les importations suivantes sont requises:
la source
la source
Au moins à partir d'Apache commons-io 2.5, la méthode IOUtils.toString () prend en charge un argument URI et renvoie le contenu des fichiers situés à l'intérieur des jars sur le chemin de classe:
la source
J'aime la réponse d'Akosicki avec le Stupid Scanner Trick. C'est le plus simple que je vois sans dépendances externes qui fonctionne dans Java 8 (et en fait tout le chemin du retour à Java 5). Voici une réponse encore plus simple si vous pouvez utiliser Java 9 ou supérieur (car il a
InputStream.readAllBytes()
été ajouté à Java 9):la source
La goyave a aussi
Files.readLines()
si vous voulez une valeur de retourList<String>
ligne par ligne:Veuillez vous référer ici pour comparer 3 façons (
BufferedReader
vs Guava'sFiles
vs Guava'sResources
) d'obtenirString
d'un fichier texte.la source
Charsets
est également à Guava. Voir ceci: google.github.io/guava/releases/23.0/api/docsVoici mon approche a bien fonctionné
la source
J'ai écrit des méthodes readResource () ici , pour pouvoir le faire en une seule invocation simple. Cela dépend de la bibliothèque Guava, mais j'aime les méthodes JDK uniquement suggérées dans d'autres réponses et je pense que je vais les changer de cette façon.
la source
Si vous incluez la goyave, vous pouvez utiliser:
(D'autres solutions mentionnent une autre méthode pour la goyave mais elles sont obsolètes)
la source
Les morues suivantes fonctionnent pour moi:
la source
Voici une solution utilisant Java 11
Files.readString
:la source
J'ai créé une méthode statique sans dépendance comme celle-ci:
la source
J'aime les utilitaires communs Apache pour ce type de choses et j'utilise ce cas d'utilisation exact (lecture de fichiers depuis classpath) lors des tests, en particulier pour la lecture de fichiers JSON dans
/src/test/resources
le cadre de tests unitaires / d'intégration. par exempleÀ des fins de test, il peut être agréable d'attraper
IOException
et de lancer unRuntimeException
- votre classe de test pourrait ressembler, par exemplela source
la source