Utilidades para leer el archivo de texto de recursos en String (Java) [cerrado]
215
¿Hay alguna utilidad que ayude a leer un archivo de texto en el recurso en una Cadena? Supongo que este es un requisito popular, pero no pude encontrar ninguna utilidad después de buscar en Google.
aclare lo que quiere decir con "archivo de texto de recursos" frente a "archivo de texto en recursos": no es fácil entender lo que está tratando de lograr.
Mat
Eso es solo un archivo de texto en classpath como "classpath *: mytext / text.txt"
Loc Phan
Respuestas:
301
Sí, Guava ofrece esto en la Resourcesclase. Por ejemplo:
URL url =Resources.getResource("foo.txt");String text =Resources.toString(url,StandardCharsets.UTF_8);
@JonSkeet Esto es genial, sin embargo, para aplicaciones web puede que no sea la mejor solución, la implementación de getResourceestá utilizando, Resource.class.getClassLoaderpero en aplicaciones web, esto podría no ser "su" cargador de clases, por lo que se recomienda (por ejemplo, en [1]) usar Thread.currentThread().getContextClassLoader().getResourceAsStreamen su lugar (referencia [1]: stackoverflow.com/questions/676250/… )
Eran Medan
2
@EranMedan: Sí, si quieres el cargador de clases de contexto, querrás usarlo explícitamente.
Jon Skeet
66
En el caso especial cuando el recurso está al lado de su clase, puede hacer lo Resources.toString(MyClass.getResource("foo.txt"), Charsets.UTF_8)que garantiza el uso del cargador de clases correcto.
Bogdan Calmac
2
com.google.common.io.Resourcesestá marcado como inestable según SonarQube
Ghilteras
1
guavaha cambiado la implementación. Para la guayaba 23, a la implementación le gusta seguir. ClassLoader loader = MoreObjects.firstNonNull( Thread.currentThread().getContextClassLoader(), Resources.class.getClassLoader());
Evitar terceros es un principio razonable. Desafortunadamente, la biblioteca central parece alérgica al modelado de casos de uso de la vida real. Mire los archivos de Java 7 y dígame por qué no se incluyó allí la lectura de todo desde un recurso classpath. O al menos usando un 'sistema de archivos' estandarizado.
Dilum Ranatunga
3
¿Es necesario, o no es necesario, cerrar también la transmisión? La guayaba cierra internamente el arroyo.
virgo47
¡También funcionó maravillosamente para mí! También estoy de acuerdo con lo de terceros: en muchas respuestas, la respuesta predeterminada siempre parece ser el uso de una biblioteca de terceros, ya sea de Apache o de otra persona.
Terje Dahl
1
cambiar CartApplication.class.getResourceAsStreama CartApplication.class.getClassLoader().getResourceAsStreampara cargar recursos en el jar actual ... como srm / test / resources
Chris DaMour
55
Si bien he usado esto, no estoy de acuerdo en evitar los paquetes de terceros. El hecho de que en Java, la única forma de leer fácilmente un archivo a cadena es con el truco del escáner es bastante triste. La alternativa al uso de una biblioteca de terceros es que todos crearán sus propios envoltorios. La guayaba para IO sin duda gana si tiene muchas necesidades para este tipo de operación. Lo que aceptaré es que no debe importar un paquete de terceros si solo tiene un lugar en su código donde desea hacer esto. Eso sería excesivo imo.
Explique por qué esto funciona, por qué es mejor que otras alternativas y cualquier consideración de rendimiento / codificación necesaria.
nanofarad
55
Es nio 2 en java 1.7. Es feture nativo de java. Para la codificación, utilice la nueva cadena (bytes, StandardCharsets.UTF_8)
Kovalsky Dmitryi
55
en mi caso necesitaba getClass().getClassLoader()pero por lo demás una gran solución!
Emmanuel Touzery
3
Esto no funcionará, una vez que la aplicación esté empaquetada en un frasco.
Daniel Bo
65
Solución Java 8+ pura y simple, fácil de usar
Este simple método a continuación funcionará bien si está utilizando Java 8 o 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()));}}}
Y también funciona con recursos en archivos jar .
Acerca de la codificación de texto: InputStreamReaderutilizará el juego de caracteres predeterminado del sistema en caso de que no especifique uno. Es posible que desee especificarlo usted mismo para evitar problemas de decodificación, como este:
newInputStreamReader(isr,StandardCharsets.UTF_8);
Evitar dependencias innecesarias
Siempre prefiera no depender de bibliotecas grandes y gordas. A menos que ya esté utilizando Guava o Apache Commons IO para otras tareas, agregar esas bibliotecas a su proyecto solo para poder leer desde un archivo parece demasiado.
Método "simple"? Debes estar bromeando
Entiendo que Java puro no hace un buen trabajo cuando se trata de hacer tareas simples como esta. Por ejemplo, así es como leemos de un archivo en Node.js:
Simple y fácil de leer (aunque a la gente todavía le gusta confiar en muchas dependencias de todos modos, principalmente debido a la ignorancia). O en Python:
with open('some-file.txt','r')as f:
content = f.read()
Es triste, pero sigue siendo simple para los estándares de Java y todo lo que tiene que hacer es copiar el método anterior a su proyecto y usarlo. Ni siquiera te pido que entiendas lo que está sucediendo allí, porque realmente no le importa a nadie. Simplemente funciona, punto :-)
@zakmck, intenta mantener tus comentarios constructivos. A medida que creces como un desarrollador maduro, aprendes que a veces quieres "reinventar la rueda". Por ejemplo, es posible que deba mantener su binario por debajo del tamaño del umbral de algo. Las bibliotecas a menudo hacen que el tamaño de su aplicación crezca en órdenes de magnitud. Se podría argumentar exactamente lo contrario de lo que dijo: "No es necesario escribir código. Sí, solo importaremos bibliotecas cada vez". ¿Realmente preferiría importar una biblioteca solo para guardar 3 líneas de código? Apuesto a que agregar la biblioteca aumentará su LOC en más que eso. La clave es el equilibrio.
Lucio Paiva
3
Bueno, no todos están ejecutando cosas en la nube. Hay sistemas integrados en todas partes que ejecutan Java, por ejemplo. Simplemente no veo su punto de criticar las respuestas que brindan enfoques totalmente válidos, dado que se menciona a sí mismo que aceptará la sugerencia de usar JDK directamente en su propio código. De todos modos, intentemos mantener los comentarios estrictamente para ayudar a mejorar las respuestas, no para discutir opiniones.
Lucio Paiva
1
Buena solución solo para JDK. Solo agregaría check si la InputStreamvariable ises nullo no.
scrutari
2
Agradable. Yo usé esto También puede considerar cerrar las transmisiones / lectores.
dimplex
1
@RobertBain Edité la respuesta para agregar información sobre la advertencia del conjunto de caracteres. Avíseme si descubre qué salió mal con el cargador de clases en AWS para que pueda agregarlo a la respuesta también. ¡Gracias!
Lucio Paiva
57
La guayaba tiene un método "toString" para leer un archivo en una cadena:
O si se trata de una transmisión de entrada, la guayaba también tiene una buena manera de hacerloString stringFromStream = CharStreams.toString(new InputStreamReader(resourceAsStream, "UTF-8"));
Prefiero "" a esto en caso de que no esté disponible
User833970
11
Del mismo modo compacto, pero con el cierre correcto de la secuencia de entrada: IOUtils.toString(this.getClass().getResource("foo.xml"), "UTF-8").
Bogdan Calmac
1
Si esta solución no funciona, intente agregar getClassLoader()a la cadena 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 qué uno tiene que especificar la codificación? No entiendo eso. Si leo el archivo, solo quiero lo que contiene, debería averiguar qué codificación es como lo hace mi editor. Cuando abro en Notepad o ++, no le digo qué codificación debería usar. Estoy usando este método y luego writeStringToFile ... pero los contenidos difieren. Obtengo tokens extraños en el archivo clonado. No entiendo por qué debería tener que especificar una codificación.
mmm
11
@Hamidan, elegir la codificación correcta es un algoritmo muy complejo. A menudo se implementa en el editor de texto, pero a veces no pueden detectar la codificación correcta. No esperaría que una API de lectura de archivos incrustara un algoritmo tan complejo para leer mi archivo.
Vincent Robert
1
@SecretService Además, esos algoritmos hacen uso de información como el idioma del sistema operativo, la configuración regional y otras configuraciones regionales, lo que significa que leer un archivo sin especificar una codificación puede funcionar en su configuración, pero no en la de otra persona.
No creo que esto funcione si el recurso se encuentra dentro de un frasco. Entonces no será un archivo.
Ville Oikarinen
16
A menudo tuve este problema yo mismo. Para evitar dependencias en proyectos pequeños, a menudo escribo una pequeña función de utilidad cuando no necesito commons io o tal. Aquí está el código para cargar el contenido del archivo en un búfer de cadena:
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());
En ese caso, es importante especificar la codificación , porque es posible que haya editado su archivo en UTF-8 y luego lo haya colocado en un archivo jar, y la computadora que abre el archivo puede tener CP-1251 como codificación de archivo nativa (por ejemplo) ; así que en este caso nunca se conoce la codificación de destino, por lo tanto, la información de codificación explícita es crucial. Además, el bucle para leer el archivo char por char parece ineficiente, pero se usa en un BufferedReader y, por lo tanto, en realidad es bastante rápido.
El archivo funciona solo para recursos classpath que son, bueno, archivos. No si son elementos en un archivo .jar, o parte de un jar gordo, una de las otras implementaciones de cargadores de clases.
Toolforger
2
Estoy usando lo siguiente para leer archivos de recursos 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;}}
Al menos a partir de Apache commons-io 2.5, el método IOUtils.toString () admite un argumento URI y devuelve el contenido de los archivos ubicados dentro de los frascos en el classpath:
Me gusta la respuesta de akosicki con Stupid Scanner Trick. Es lo más simple que veo sin dependencias externas que funciona en Java 8 (y de hecho hasta Java 5). Aquí hay una respuesta aún más simple si puede usar Java 9 o superior (ya que InputStream.readAllBytes()se agregó en Java 9):
String text =newString(AppropriateClass.class.getResourceAsStream("foo.txt").readAllBytes());
¿De dónde vienen los IOUtils? La fuente debe ser referenciada claramente.
ehecatl
0
He escrito métodos readResource () aquí , para poder hacerlo en una simple invocación. Depende de la biblioteca de Guava, pero me gustan los métodos solo JDK sugeridos en otras respuestas y creo que los cambiaré de esa manera.
publicclassUtils{publicstaticString readResource(String name)throwsURISyntaxException,IOException{
var uri =Utils.class.getResource("/"+ name).toURI();
var path =Paths.get(uri);returnFiles.readString(path);}}
Me gustan las utilidades de Apache commons para este tipo de cosas y uso este caso de uso exacto (lectura de archivos de classpath) ampliamente cuando se realizan pruebas, especialmente para leer archivos JSON /src/test/resourcescomo parte de las pruebas de unidad / integración. p.ej
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 fines de prueba, puede ser agradable atrapar IOExceptiony lanzar un RuntimeException- su clase de prueba podría verse, por ejemplo,
@Testpublicvoid shouldDoSomething (){String json =FileUtils.getResource("/json/input.json");// Use json as part of test ...}
Respuestas:
Sí, Guava ofrece esto en la
Resources
clase. Por ejemplo:fuente
getResource
está utilizando,Resource.class.getClassLoader
pero en aplicaciones web, esto podría no ser "su" cargador de clases, por lo que se recomienda (por ejemplo, en [1]) usarThread.currentThread().getContextClassLoader().getResourceAsStream
en su lugar (referencia [1]: stackoverflow.com/questions/676250/… )Resources.toString(MyClass.getResource("foo.txt"), Charsets.UTF_8)
que garantiza el uso del cargador de clases correcto.com.google.common.io.Resources
está marcado como inestable según SonarQubeguava
ha cambiado la implementación. Para la guayaba 23, a la implementación le gusta seguir.ClassLoader loader = MoreObjects.firstNonNull( Thread.currentThread().getContextClassLoader(), Resources.class.getClassLoader());
Puede usar el viejo truco en línea Stupid Scanner para hacer eso sin ninguna dependencia adicional como guayaba:
Chicos, no utilicen material de terceros a menos que realmente lo necesiten. Ya hay mucha funcionalidad en el JDK.
fuente
CartApplication.class.getResourceAsStream
aCartApplication.class.getClassLoader().getResourceAsStream
para cargar recursos en el jar actual ... como srm / test / resourcesPara java 7:
fuente
getClass().getClassLoader()
pero por lo demás una gran solución!Solución Java 8+ pura y simple, fácil de usar
Este simple método a continuación funcionará bien si está utilizando Java 8 o superior:
Y también funciona con recursos en archivos jar .
Acerca de la codificación de texto:
InputStreamReader
utilizará el juego de caracteres predeterminado del sistema en caso de que no especifique uno. Es posible que desee especificarlo usted mismo para evitar problemas de decodificación, como este:Evitar dependencias innecesarias
Siempre prefiera no depender de bibliotecas grandes y gordas. A menos que ya esté utilizando Guava o Apache Commons IO para otras tareas, agregar esas bibliotecas a su proyecto solo para poder leer desde un archivo parece demasiado.
Método "simple"? Debes estar bromeando
Entiendo que Java puro no hace un buen trabajo cuando se trata de hacer tareas simples como esta. Por ejemplo, así es como leemos de un archivo en Node.js:
Simple y fácil de leer (aunque a la gente todavía le gusta confiar en muchas dependencias de todos modos, principalmente debido a la ignorancia). O en Python:
Es triste, pero sigue siendo simple para los estándares de Java y todo lo que tiene que hacer es copiar el método anterior a su proyecto y usarlo. Ni siquiera te pido que entiendas lo que está sucediendo allí, porque realmente no le importa a nadie. Simplemente funciona, punto :-)
fuente
InputStream
variableis
esnull
o no.La guayaba tiene un método "toString" para leer un archivo en una cadena:
Este método no requiere que el archivo esté en el classpath (como en la respuesta anterior de Jon Skeet ).
fuente
String stringFromStream = CharStreams.toString(new InputStreamReader(resourceAsStream, "UTF-8"));
yegor256 ha encontrado una buena solución usando Apache Commons IO :
fuente
IOUtils.toString(this.getClass().getResource("foo.xml"), "UTF-8")
.getClassLoader()
a la cadena de métodos:String text = IOUtils.toString( getClass().getClassLoader().getResourceAsStream("foo.xml"), StandardCharsets.UTF_8);
apache-commons-io tiene un nombre de utilidad
FileUtils
:fuente
A menudo tuve este problema yo mismo. Para evitar dependencias en proyectos pequeños, a menudo escribo una pequeña función de utilidad cuando no necesito commons io o tal. Aquí está el código para cargar el contenido del archivo en un búfer de cadena:
En ese caso, es importante especificar la codificación , porque es posible que haya editado su archivo en UTF-8 y luego lo haya colocado en un archivo jar, y la computadora que abre el archivo puede tener CP-1251 como codificación de archivo nativa (por ejemplo) ; así que en este caso nunca se conoce la codificación de destino, por lo tanto, la información de codificación explícita es crucial. Además, el bucle para leer el archivo char por char parece ineficiente, pero se usa en un BufferedReader y, por lo tanto, en realidad es bastante rápido.
fuente
Puede usar el siguiente código de Java
fuente
Si desea obtener su Cadena de un recurso de proyecto como el archivo testcase / foo.json en src / main / resources en su proyecto, haga lo siguiente:
Tenga en cuenta que falta el método getClassLoader () en algunos de los otros ejemplos.
fuente
Use FileUtils de Apache commons. Tiene un método readFileToString
fuente
Estoy usando lo siguiente para leer archivos de recursos de
classpath
:No se requieren dependencias de terceros.
fuente
Con un conjunto de importaciones estáticas, la solución de guayaba puede ser muy compacta:
Se requieren las siguientes importaciones:
fuente
fuente
Al menos a partir de Apache commons-io 2.5, el método IOUtils.toString () admite un argumento URI y devuelve el contenido de los archivos ubicados dentro de los frascos en el classpath:
fuente
Me gusta la respuesta de akosicki con Stupid Scanner Trick. Es lo más simple que veo sin dependencias externas que funciona en Java 8 (y de hecho hasta Java 5). Aquí hay una respuesta aún más simple si puede usar Java 9 o superior (ya que
InputStream.readAllBytes()
se agregó en Java 9):fuente
La guayaba también tiene
Files.readLines()
si desea un valor de retorno comoList<String>
línea por línea:Consulte aquí para comparar 3 formas (
BufferedReader
frente a Guava'sFiles
versus Guava'sResources
) para obtenerString
de un archivo de texto.fuente
Charsets
también está en Guava. Vea esto: google.github.io/guava/releases/23.0/api/docsAquí está mi enfoque funcionó bien
fuente
He escrito métodos readResource () aquí , para poder hacerlo en una simple invocación. Depende de la biblioteca de Guava, pero me gustan los métodos solo JDK sugeridos en otras respuestas y creo que los cambiaré de esa manera.
fuente
Si incluye guayaba, puede usar:
(Otras soluciones mencionaron otro método para la guayaba pero están en desuso)
fuente
Los siguientes bacalaos funcionan para mí:
fuente
Aquí hay una solución que usa Java 11
Files.readString
:fuente
Hice un método estático de NO dependencia como este:
fuente
Me gustan las utilidades de Apache commons para este tipo de cosas y uso este caso de uso exacto (lectura de archivos de classpath) ampliamente cuando se realizan pruebas, especialmente para leer archivos JSON
/src/test/resources
como parte de las pruebas de unidad / integración. p.ejPara fines de prueba, puede ser agradable atrapar
IOException
y lanzar unRuntimeException
- su clase de prueba podría verse, por ejemplo,fuente
fuente