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.
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);
@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 =newScanner(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.
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.
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
*/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()));}}}
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:
newInputStreamReader(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:
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 :-)
@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:
Ou se é um fluxo de entrada, goiaba tem uma boa maneira para isso tambémString stringFromStream = CharStreams.toString(new InputStreamReader(resourceAsStream, "UTF-8"));
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);
URL url =Resources.getResource("myFile.txt");File myFile =newFile(url.toURI());String content =FileUtils.readFileToString(myFile,"UTF-8");// or any other encoding
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.
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 =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());
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.
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:
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:
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;}}
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:
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 =newString(AppropriateClass.class.getResourceAsStream("foo.txt").readAllBytes());
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.
publicclassUtils{publicstaticString readResource(String name)throwsURISyntaxException,IOException{
var uri =Utils.class.getResource("/"+ name).toURI();
var path =Paths.get(uri);returnFiles.readString(path);}}
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
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);}}}
Para fins de teste, pode ser bom pegar IOExceptione lançar uma RuntimeException- sua classe de teste pode parecer, por exemplo,
@Testpublicvoid shouldDoSomething (){String json =FileUtils.getResource("/json/input.json");// Use json as part of test ...}
Respostas:
Sim, o Guava fornece isso na
Resources
classe. Por exemplo:fonte
getResource
está sendo usada,Resource.class.getClassLoader
mas em aplicativos da web, esse pode não ser o "seu" carregador de classes, por isso é recomendável (por exemplo, em [1]) usarThread.currentThread().getContextClassLoader().getResourceAsStream
em vez disso (referência [1]: stackoverflow.com/questions/676250/… )Resources.toString(MyClass.getResource("foo.txt"), Charsets.UTF_8)
que garante o uso do carregador de classes correto.com.google.common.io.Resources
está marcado como instável de acordo com o SonarQubeguava
mudou a implementação. Para a goiaba 23, a implementação gosta de seguir.ClassLoader loader = MoreObjects.firstNonNull( Thread.currentThread().getContextClassLoader(), Resources.class.getClassLoader());
Você pode usar o antigo truque do Stupid Scanner oneliner para fazer isso sem nenhuma dependência adicional como a goiaba:
Pessoal, não use coisas de terceiros, a menos que você realmente precise disso. Já existe muita funcionalidade no JDK.
fonte
CartApplication.class.getResourceAsStream
paraCartApplication.class.getClassLoader().getResourceAsStream
carregar recursos nos atuais jar..like srm / teste / recursosPara java 7:
fonte
getClass().getClassLoader()
outra solução ótima!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:
E também funciona com recursos em arquivos jar .
Sobre a codificação de texto:
InputStreamReader
usará 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: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:
Simples e fácil de ler (embora as pessoas ainda gostem de contar com muitas dependências, principalmente devido à ignorância). Ou em Python:
É 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 :-)
fonte
InputStream
variávelis
énull
ou não.A Goiaba possui um método "toString" para ler um arquivo em uma String:
Este método não requer que o arquivo esteja no caminho de classe (como na resposta anterior de Jon Skeet ).
fonte
String stringFromStream = CharStreams.toString(new InputStreamReader(resourceAsStream, "UTF-8"));
O yegor256 encontrou uma boa solução usando o Apache Commons IO :
fonte
IOUtils.toString(this.getClass().getResource("foo.xml"), "UTF-8")
.getClassLoader()
à cadeia de métodos:String text = IOUtils.toString( getClass().getClassLoader().getResourceAsStream("foo.xml"), StandardCharsets.UTF_8);
apache-commons-io tem um nome de utilitário
FileUtils
:fonte
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:
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.
fonte
Você pode usar o seguinte código Java
fonte
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:
Observe que o método getClassLoader () está ausente em alguns dos outros exemplos.
fonte
Use o FileUtils do Apache commons. Possui um método readFileToString
fonte
Estou usando o seguinte para ler arquivos de recursos em
classpath
:Não são necessárias dependências de terceiros.
fonte
Com o conjunto de importações estáticas, a solução Guava pode ser uma linha muito compacta:
As seguintes importações são necessárias:
fonte
fonte
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:
fonte
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):fonte
A goiaba também possui
Files.readLines()
se você deseja um valor de retorno comoList<String>
linha por linha:Consulte aqui para comparar três maneiras (
BufferedReader
vs. GuavaFiles
vs. GuavaResources
) de obterString
um arquivo de texto.fonte
Charsets
também está na Goiaba. Veja isto: google.github.io/guava/releases/23.0/api/docsAqui está a minha abordagem funcionou bem
fonte
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.
fonte
Se você incluir o Goiaba, poderá usar:
(Outras soluções mencionaram outro método para a goiaba, mas estão obsoletas)
fonte
Os seguintes códigos funcionam para mim:
fonte
Aqui está uma solução usando Java 11
Files.readString
:fonte
Eu criei o método estático de dependência NO, como este:
fonte
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/resources
como parte do teste de unidade / integração. por exemploPara fins de teste, pode ser bom pegar
IOException
e lançar umaRuntimeException
- sua classe de teste pode parecer, por exemplo,fonte
fonte