Utilitários para ler o arquivo de texto de recurso em String (Java) [fechado]

215

Existe algum utilitário que ajude a ler um arquivo de texto no recurso em uma String. Suponho que esse seja um requisito popular, mas não consegui encontrar nenhum utilitário após pesquisar no Google.

Loc Phan
fonte
1
esclareça o que você quer dizer com "arquivo de texto de recurso" vs "arquivo de texto de recurso" - não é fácil entender o que você está tentando alcançar.
Mat
Isso é apenas um arquivo de texto sob o classpath como "classpath *: mytext / text.txt"
Loc Phan

Respostas:

301

Sim, o Guava fornece isso na Resourcesclasse. Por exemplo:

URL url = Resources.getResource("foo.txt");
String text = Resources.toString(url, StandardCharsets.UTF_8);
Jon Skeet
fonte
21
@JonSkeet Isso é ótimo, no entanto, para aplicativos da web, pode não ser a melhor solução, a implementação getResourceestá sendo usada, Resource.class.getClassLoadermas em aplicativos da web, esse pode não ser o "seu" carregador de classes, por isso é recomendável (por exemplo, em [1]) usar Thread.currentThread().getContextClassLoader().getResourceAsStreamem vez disso (referência [1]: stackoverflow.com/questions/676250/… )
Eran Medan 13/13
2
@EranMedan: Sim, se você quiser o carregador de classes de contexto, você o usará explicitamente.
Jon Skeet
6
No caso especial, quando o recurso estiver próximo à sua classe, você poderá fazer o Resources.toString(MyClass.getResource("foo.txt"), Charsets.UTF_8)que garante o uso do carregador de classes correto.
Bogdan Calmac
2
com.google.common.io.Resourcesestá marcado como instável de acordo com o SonarQube
Ghilteras
1
guavamudou a implementação. Para a goiaba 23, a implementação gosta de seguir. ClassLoader loader = MoreObjects.firstNonNull( Thread.currentThread().getContextClassLoader(), Resources.class.getClassLoader());
xxy 22/02
170

Você pode usar o antigo truque do Stupid Scanner oneliner para fazer isso sem nenhuma dependência adicional como a goiaba:

String text = new Scanner(AppropriateClass.class.getResourceAsStream("foo.txt"), "UTF-8").useDelimiter("\\A").next();

Pessoal, não use coisas de terceiros, a menos que você realmente precise disso. Já existe muita funcionalidade no JDK.

akosicki
fonte
41
Evitar terceiros é um princípio razoável. Infelizmente, a biblioteca principal parece alérgica à modelagem de casos de uso da vida real. Veja os arquivos do Java 7 e me diga por que a leitura de tudo, de um recurso de caminho de classe, não foi incluída lá? Ou pelo menos usando um 'sistema de arquivos' padronizado.
Dilum Ranatunga
3
É - ou não é - necessário fechar o fluxo também? Goiaba fecha internamente o córrego.
virgo47
Trabalhou lindamente para mim também! Também concordo com a questão de terceiros: em muitas respostas, a resposta padrão sempre parece ser usar alguma biblioteca de terceiros - seja do Apache ou de outra pessoa.
Terje Dahl
1
mudar CartApplication.class.getResourceAsStreampara CartApplication.class.getClassLoader().getResourceAsStreamcarregar recursos nos atuais jar..like srm / teste / recursos
Chris Damour
5
Enquanto eu usei isso, discordo completamente de evitar pacotes de terceiros. O fato de que em Java, a única maneira de ler facilmente um arquivo para string é com o truque do scanner é bastante triste. A alternativa ao uso de uma biblioteca de terceiros é que todos criarão seus próprios wrappers. A goiaba para mãos de IO vence, se você tiver muitas necessidades para esse tipo de operação. Onde eu concordo é que você não deve importar um pacote de terceiros se você tiver apenas um lugar no código em que deseja fazer isso. Isso seria um exagero.
precisa
90

Para java 7:

new String(Files.readAllBytes(Paths.get(getClass().getResource("foo.txt").toURI())));
Kovalsky Dmitryi
fonte
3
Explique por favor por que isso funciona, por que é melhor do que outras alternativas e quaisquer considerações de desempenho / codificação necessárias.
Nanofarad
5
É nio 2 em java 1.7. É um feto nativo de java. Para codificação, use new String (bytes, StandardCharsets.UTF_8)
Kovalsky Dmitryi
5
no meu caso, eu precisava de getClass().getClassLoader()outra solução ótima!
Emmanuel Touzery
3
Isso não funcionará, uma vez que o aplicativo é empacotado em um frasco.
Daniel Bo
65

Solução pura e simples, compatível com jar, Java 8+

Este método simples abaixo funcionará bem se você estiver usando o Java 8 ou superior:

/**
 * 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()));
        }
    }
}

E também funciona com recursos em arquivos jar .

Sobre a codificação de texto: InputStreamReaderusará o conjunto de caracteres padrão do sistema caso você não especifique um. Você pode especificá-lo para evitar problemas de decodificação, como este:

new InputStreamReader(isr, StandardCharsets.UTF_8);

Evite dependências desnecessárias

Sempre prefira não depender de grandes bibliotecas gordas. A menos que você já esteja usando o Guava ou o Apache Commons IO para outras tarefas, adicionar essas bibliotecas ao seu projeto apenas para poder ler de um arquivo parece um pouco demais.

Método "simples"? Você deve estar brincando comigo

Eu entendo que o Java puro não faz um bom trabalho quando se trata de executar tarefas simples como essa. Por exemplo, é assim que lemos de um arquivo no Node.js:

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

Simples e fácil de ler (embora as pessoas ainda gostem de contar com muitas dependências, principalmente devido à ignorância). Ou em Python:

with open('some-file.txt', 'r') as f:
    content = f.read()

É triste, mas ainda é simples para os padrões do Java e tudo o que você precisa fazer é copiar o método acima para o seu projeto e usá-lo. Eu nem peço que você entenda o que está acontecendo lá, porque realmente não importa para ninguém. Apenas funciona, ponto final :-)

Lucio Paiva
fonte
4
@zakmck, tente manter seus comentários construtivos. À medida que você cresce como desenvolvedor maduro, aprende que às vezes deseja "reinventar a roda". Por exemplo, você pode precisar manter seu binário abaixo de algum tamanho limite. As bibliotecas geralmente fazem o tamanho do seu aplicativo aumentar por ordens de magnitude. Alguém poderia argumentar exatamente o oposto do que você disse: "Não há necessidade de escrever código. Sim, vamos apenas importar bibliotecas sempre". Você realmente prefere importar uma biblioteca apenas para economizar três linhas de código? Aposto que adicionar a biblioteca aumentará seu LOC em mais do que isso. A chave é o equilíbrio.
Lucio Paiva
3
Bem, nem todo mundo está executando coisas na nuvem. Existem sistemas embarcados em todos os lugares executando Java, por exemplo. Eu simplesmente não vejo o seu ponto de criticar respostas que fornecem abordagens totalmente válidas, desde que você mencione que aceita a sugestão de usar o JDK diretamente em seu próprio código. De qualquer forma, vamos tentar manter os comentários estritamente para ajudar a melhorar as respostas, não para discutir opiniões.
Lucio Paiva
1
Boa solução apenas para JDK. Eu só adicionaria check se a InputStreamvariável isé nullou não.
Scrutari
2
Agradável. Eu usei isso. Você pode considerar fechar os fluxos / leitores também.
DIMPLEX
1
@RobertBain Editei a resposta para adicionar informações sobre o aviso de charset. Deixe-me saber se você descobrir o que deu errado com o carregador de classes na AWS, para que eu possa adicioná-lo à resposta também. Obrigado!
Lucio Paiva
57

A Goiaba possui um método "toString" para ler um arquivo em uma String:

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

Este método não requer que o arquivo esteja no caminho de classe (como na resposta anterior de Jon Skeet ).

Luciano Fiandesio
fonte
2
Ou se é um fluxo de entrada, goiaba tem uma boa maneira para isso tambémString stringFromStream = CharStreams.toString(new InputStreamReader(resourceAsStream, "UTF-8"));
Eran Medan
1
Isso foi preterido no Goiaba 24.1
Andrey
47

O yegor256 encontrou uma boa solução usando o Apache Commons IO :

import org.apache.commons.io.IOUtils;

String text = IOUtils.toString(this.getClass().getResourceAsStream("foo.xml"),
                               "UTF-8");
Stefan Endrullis
fonte
Eu prefiro "" a este caso, isso não está disponível
user833970 15/01
11
Assim como compacto, mas com fechamento adequado do fluxo de entrada: IOUtils.toString(this.getClass().getResource("foo.xml"), "UTF-8").
Bogdan Calmac
1
Se esta solução não funcionar, tente adicionar getClassLoader()à cadeia de métodos: String text = IOUtils.toString( getClass().getClassLoader().getResourceAsStream("foo.xml"), StandardCharsets.UTF_8);
Abdull 4/17
39

apache-commons-io tem um nome de utilitário FileUtils:

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

String content = FileUtils.readFileToString(myFile, "UTF-8");  // or any other encoding
Andreas Dolk
fonte
1
Por que alguém tem que especificar a codificação, eu não entendo isso. Se eu ler o arquivo, eu só quero o que há nele, ele deve descobrir qual codificação é como meu editor faz. Quando abro no Bloco de notas ou ++, não digo qual codificação ele deve usar. Estou usando esse método e depois escrevoStringToFile ... mas o conteúdo é diferente. Recebo tokens estranhos no arquivo clonado. Não entendo por que devo especificar uma codificação.
mmm
11
@ Hamidan, escolher a codificação correta é um algoritmo muito complexo. Geralmente é implementado no editor de texto, mas às vezes eles não conseguem detectar a codificação correta. Eu não esperaria que um API de leitura de arquivo incorporasse um algoritmo tão complexo para ler meu arquivo.
Vincent Robert
1
@SecretService Além disso, esses algoritmos usam informações como idioma do sistema operacional, localidade e outras configurações regionais, o que significa que a leitura de um arquivo sem especificar uma codificação pode funcionar na sua configuração, mas não na de outra pessoa.
Feuermurmel
Apache FileUtils . readLines (arquivo) e copyURLToFile (URL, tempFile).
Yash
2
Eu não acho que isso funcionará se o recurso for encontrado dentro de um jar. Então não será um arquivo.
Ville Oikarinen
16

Muitas vezes eu também tive esse problema. Para evitar dependências em projetos pequenos, costumo escrever uma função de utilitário pequeno quando não preciso de bens comuns io ou algo assim. Aqui está o código para carregar o conteúdo do arquivo em um buffer de cadeia:

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

A especificação da codificação é importante nesse caso, porque você pode ter editado seu arquivo em UTF-8 e, em seguida, colocado em um jar, e o computador que abre o arquivo pode ter o CP-1251 como codificação de arquivo nativo (por exemplo) ; portanto, nesse caso, você nunca conhece a codificação de destino; portanto, as informações de codificação explícitas são cruciais. Além disso, o loop para ler o arquivo char por char parece ineficiente, mas é usado em um BufferedReader e, portanto, bastante rápido.

Harry Karadimas
fonte
15

Você pode usar o seguinte código Java

new String(Files.readAllBytes(Paths.get(getClass().getResource("example.txt").toURI())));
Raghu K Nair
fonte
Quais instruções de importação são necessárias para obter as classes "Arquivos" e "Caminhos"?
Steve Scherer
1
ambos são parte do pacote java.nio.file disponível a partir JDK 7+
Raghu K Nair
Não funciona quando em um arquivo jar.
Displee
4

Se você deseja obter sua String de um recurso do projeto, como o arquivo testcase / foo.json em src / main / resources em seu projeto, faça o seguinte:

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

Observe que o método getClassLoader () está ausente em alguns dos outros exemplos.

Witbrock
fonte
2

Use o FileUtils do Apache commons. Possui um método readFileToString

Suraj Chandran
fonte
O arquivo funciona apenas para recursos do caminho de classe que são, bem, arquivos. Não se forem elementos em um arquivo .jar ou parte de um jar de gordura, uma das outras implementações do carregador de classes.
toolforger 30/04
2

Estou usando o seguinte para ler arquivos de recursos em 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() : "";
        }
    }
}

Não são necessárias dependências de terceiros.

BullyWiiPlaza
fonte
1

Com o conjunto de importações estáticas, a solução Guava pode ser uma linha muito compacta:

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

As seguintes importações são necessárias:

import static com.google.common.io.Resources.getResource
import static com.google.common.io.Resources.toString
import static java.nio.charset.StandardCharsets.UTF_8
Michal Kordas
fonte
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;
    }
}
sklimkovitch
fonte
1

Pelo menos a partir do Apache commons-io 2.5, o método IOUtils.toString () suporta um argumento URI e retorna o conteúdo dos arquivos localizados dentro dos jars no caminho de classe:

IOUtils.toString(SomeClass.class.getResource(...).toURI(), ...)
user1050755
fonte
1

Gosto da resposta de akosicki com o Stupid Scanner Trick. É o mais simples que vejo, sem dependências externas, que funciona no Java 8 (e, de fato, até o Java 5). Aqui está uma resposta ainda mais simples se você pode usar o Java 9 ou superior (já que InputStream.readAllBytes()foi adicionado no Java 9):

String text = new String(AppropriateClass.class.getResourceAsStream("foo.txt").readAllBytes());
Gary S.
fonte
0

A goiaba também possui Files.readLines()se você deseja um valor de retorno como List<String>linha por linha:

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

Consulte aqui para comparar três maneiras ( BufferedReadervs. Guava Filesvs. Guava Resources) de obter Stringum arquivo de texto.

philipjkim
fonte
O que é a classe Charsets? Não é nativo
e-info128
O @ e-info128 Charsetstambém está na Goiaba. Veja isto: google.github.io/guava/releases/23.0/api/docs
philipjkim
0

Aqui está a minha abordagem funcionou bem

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
    }
}
Java_Fire_Within
fonte
2
De onde vêm os IOUtils? A fonte deve ser referenciada claramente.
ehecatl
0

Eu escrevi métodos readResource () aqui , para poder fazer isso em uma chamada simples. Depende da biblioteca do Guava, mas eu gosto dos métodos somente JDK sugeridos em outras respostas e acho que vou mudar dessa maneira.

zakmck
fonte
0

Se você incluir o Goiaba, poderá usar:

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

(Outras soluções mencionaram outro método para a goiaba, mas estão obsoletas)

jolumg
fonte
0

Os seguintes códigos funcionam para mim:

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");
Vicky
fonte
0

Aqui está uma solução usando 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);
    }
}
Dillon Ryan Redding
fonte
0

Eu criei o método estático de dependência NO, como este:

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
}
Espresso
fonte
0

Eu gosto dos utilitários comuns do Apache para esse tipo de material e uso esse caso de uso exato (lendo arquivos do caminho de classe) extensivamente ao testar, especialmente para ler arquivos JSON /src/test/resourcescomo parte do teste de unidade / integração. por exemplo

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

}

Para fins de teste, pode ser bom pegar IOExceptione lançar uma RuntimeException- sua classe de teste pode parecer, por exemplo,

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

        // Use json as part of test ...
    }
bobmarksie
fonte
-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");
Khắc Nghĩa Từ
fonte
Por favor, adicione uma breve explicação à sua resposta.
Nikolay Mihaylov