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.


1
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);

21
@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 = new Scanner(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.


41
É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.
Kenny Cason

90

Pour java 7:

new String(Files.readAllBytes(Paths.get(getClass().getResource("foo.txt").toURI())));

3
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
 */
static String getResourceFileAsString(String fileName) throws IOException {
    ClassLoader classLoader = ClassLoader.getSystemClassLoader();
    try (InputStream is = classLoader.getResourceAsStream(fileName)) {
        if (is == null) return null;
        try (InputStreamReader isr = new InputStreamReader(is);
             BufferedReader reader = new BufferedReader(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:

new InputStreamReader(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:

const fs = require("fs");
const contents = fs.readFileSync("some-file.txt", "utf-8");

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 :-)


4
@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:

import com.google.common.base.Charsets;
import com.google.common.io.Files;

String content = Files.toString(new File("/home/x1/text.log"), Charsets.UTF_8);

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 ).


2
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"));
Eran Medan

1
Ceci est obsolète dans Guava 24.1
Andrey

47

yegor256 a trouvé une bonne solution en utilisant Apache Commons IO :

import org.apache.commons.io.IOUtils;

String text = IOUtils.toString(this.getClass().getResourceAsStream("foo.xml"),
                               "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);
Abdull

39

apache-commons-io a un nom d'utilitaire FileUtils:

URL url = Resources.getResource("myFile.txt");
File myFile = new File(url.toURI());

String content = FileUtils.readFileToString(myFile, "UTF-8");  // or any other encoding

1
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.
Feuermurmel

Apache FileUtils . readLines (fichier) & copyURLToFile (URL, tempFile).
Yash

2
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 = new StringBuffer();

BufferedReader br = new BufferedReader(new InputStreamReader(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.


15

Vous pouvez utiliser le code suivant Java

new String(Files.readAllBytes(Paths.get(getClass().getResource("example.txt").toURI())));

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:

String myString= 
 new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("testcase/foo.json").toURI())));

Notez que la méthode getClassLoader () est manquante dans certains des autres exemples.


2

Utilisez FileUtils d'Apache commons. Il a une méthode readFileToString


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:

import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.Scanner;

public class ResourceUtilities
{
    public static String resourceToString(String filePath) throws IOException, URISyntaxException
    {
        try (InputStream inputStream = ResourceUtilities.class.getClassLoader().getResourceAsStream(filePath))
        {
            return inputStreamToString(inputStream);
        }
    }

    private static String inputStreamToString(InputStream inputStream)
    {
        try (Scanner scanner = new Scanner(inputStream).useDelimiter("\\A"))
        {
            return scanner.hasNext() ? scanner.next() : "";
        }
    }
}

Aucune dépendance tierce n'est requise.


1

Avec un ensemble d'importations statiques, la solution de goyave peut être très compacte:

toString(getResource("foo.txt"), UTF_8);

Les importations suivantes sont requises:

import static com.google.common.io.Resources.getResource
import static com.google.common.io.Resources.toString
import static java.nio.charset.StandardCharsets.UTF_8

1
package test;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class Main {
    public static void 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" FOLDER
    public static String getFileFromResources(String fileName) throws Exception {
        ClassLoader classLoader = Main.class.getClassLoader();
        InputStream stream = classLoader.getResourceAsStream(fileName);
        String text = null;
        try (Scanner scanner = new Scanner(stream, StandardCharsets.UTF_8.name())) {
            text = scanner.useDelimiter("\\A").next();
        }
        return text;
    }
}

1

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:

IOUtils.toString(SomeClass.class.getResource(...).toURI(), ...)

1

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 = new String(AppropriateClass.class.getResourceAsStream("foo.txt").readAllBytes());

0

La goyave a aussi Files.readLines()si vous voulez une valeur de retour List<String>ligne par ligne:

List<String> lines = Files.readLines(new File("/file/path/input.txt"), Charsets.UTF_8);

Veuillez vous référer ici pour comparer 3 façons ( BufferedReadervs Guava's Filesvs Guava's Resources) d'obtenir Stringd'un fichier texte.


Qu'est-ce que la classe Charsets? n'est pas natif
e-info128

@ e-info128 Charsetsest également à Guava. Voir ceci: google.github.io/guava/releases/23.0/api/docs
philipjkim

0

Voici mon approche a bien fonctionné

public String getFileContent(String fileName) {
    String filePath = "myFolder/" + fileName+ ".json";
    try(InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath)) {
        return IOUtils.toString(stream, "UTF-8");
    } catch (IOException e) {
        // Please print your Exception
    }
}

2
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.


0

Si vous incluez la goyave, vous pouvez utiliser:

String fileContent = Files.asCharSource(new File(filename), Charset.forName("UTF-8")).read();

(D'autres solutions mentionnent une autre méthode pour la goyave mais elles sont obsolètes)


0

Les morues suivantes fonctionnent pour moi:

compile group: 'commons-io', name: 'commons-io', version: '2.6'

@Value("classpath:mockResponse.json")
private Resource mockResponse;

String mockContent = FileUtils.readFileToString(mockResponse.getFile(), "UTF-8");

0

Voici une solution utilisant Java 11 Files.readString:

public class Utils {
    public static String readResource(String name) throws URISyntaxException, IOException {
        var uri = Utils.class.getResource("/" + name).toURI();
        var path = Paths.get(uri);
        return Files.readString(path);
    }
}

0

J'ai créé une méthode statique sans dépendance comme celle-ci:

import java.nio.file.Files;
import java.nio.file.Paths;

public class ResourceReader {
    public  static String asString(String resourceFIleName) {
        try  {
            return new String(Files.readAllBytes(Paths.get(new CheatClassLoaderDummyClass().getClass().getClassLoader().getResource(resourceFIleName).toURI())));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
class CheatClassLoaderDummyClass{//cheat class loader - for sql file loading
}

0

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

public class FileUtils {

    public static String getResource(String classpathLocation) {
        try {
            String message = IOUtils.toString(FileUtils.class.getResourceAsStream(classpathLocation),
                    Charset.defaultCharset());
            return message;
        }
        catch (IOException e) {
            throw new RuntimeException("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

    @Test
    public void shouldDoSomething () {
        String json = FileUtils.getResource("/json/input.json");

        // Use json as part of test ...
    }

-2
public static byte[] readResoureStream(String resourcePath) throws IOException {
    ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
    InputStream in = CreateBffFile.class.getResourceAsStream(resourcePath);

    //Create buffer
    byte[] buffer = new byte[4096];
    for (;;) {
        int nread = in.read(buffer);
        if (nread <= 0) {
            break;
        }
        byteArray.write(buffer, 0, nread);
    }
    return byteArray.toByteArray();
}

Charset charset = StandardCharsets.UTF_8;
String content = new   String(FileReader.readResoureStream("/resource/...*.txt"), charset);
String lines[] = content.split("\\n");

Veuillez ajouter une brève explication à votre réponse.
Nikolay Mihaylov
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.