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.

Loc Phan
fuente
1
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);
Jon Skeet
fuente
21
@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());
xxy
170

Puede usar el viejo truco en línea Stupid Scanner para hacer eso sin ninguna dependencia adicional como guayaba:

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

Chicos, no utilicen material de terceros a menos que realmente lo necesiten. Ya hay mucha funcionalidad en el JDK.

akosicki
fuente
41
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.
Kenny Cason
90

Para java 7:

new String(Files.readAllBytes(Paths.get(getClass().getResource("foo.txt").toURI())));
Kovalsky Dmitryi
fuente
3
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
 */
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()));
        }
    }
}

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:

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

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

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

Lucio Paiva
fuente
44
@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:

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 no requiere que el archivo esté en el classpath (como en la respuesta anterior de Jon Skeet ).

Luciano Fiandesio
fuente
2
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"));
Eran Medan
1
Esto está en desuso en Guava 24.1
Andrey
47

yegor256 ha encontrado una buena solución usando Apache Commons IO :

import org.apache.commons.io.IOUtils;

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

apache-commons-io tiene un nombre de utilidad 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
fuente
1
¿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.
Feuermurmel
Apache FileUtils . readLines (archivo) y copyURLToFile (URL, tempFile).
Yash
2
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 = 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());   

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.

Harry Karadimas
fuente
15

Puede usar el siguiente código de Java

new String(Files.readAllBytes(Paths.get(getClass().getResource("example.txt").toURI())));
Raghu K Nair
fuente
¿Qué declaraciones de importación son necesarias para extraer las clases "Archivos" y "Rutas"?
Steve Scherer
1
ambos son parte del paquete java.nio.file disponible de JDK 7+
Raghu K Nair
No funciona cuando está en un archivo jar.
Displee
4

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:

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

Tenga en cuenta que falta el método getClassLoader () en algunos de los otros ejemplos.

Witbrock
fuente
2

Use FileUtils de Apache commons. Tiene un método readFileToString

Suraj Chandran
fuente
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:

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() : "";
        }
    }
}

No se requieren dependencias de terceros.

BullyWiiPlaza
fuente
1

Con un conjunto de importaciones estáticas, la solución de guayaba puede ser muy compacta:

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

Se requieren las siguientes importaciones:

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
fuente
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
fuente
1

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:

IOUtils.toString(SomeClass.class.getResource(...).toURI(), ...)
usuario1050755
fuente
1

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

La guayaba también tiene Files.readLines()si desea un valor de retorno como List<String>línea por línea:

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

Consulte aquí para comparar 3 formas ( BufferedReaderfrente a Guava's Filesversus Guava's Resources) para obtener Stringde un archivo de texto.

philipjkim
fuente
¿Qué es la clase Charsets? no es nativo
e-info128
@ e-info128 Charsetstambién está en Guava. Vea esto: google.github.io/guava/releases/23.0/api/docs
philipjkim
0

Aquí está mi enfoque funcionó bien

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

zakmck
fuente
0

Si incluye guayaba, puede usar:

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

(Otras soluciones mencionaron otro método para la guayaba pero están en desuso)

jolumg
fuente
0

Los siguientes bacalaos funcionan para mí:

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
fuente
0

Aquí hay una solución que usa 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
fuente
0

Hice un método estático de NO dependencia 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
}
Café exprés
fuente
0

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

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 fines de prueba, puede ser agradable atrapar IOExceptiony lanzar un RuntimeException- su clase de prueba podría verse, por ejemplo,

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

        // Use json as part of test ...
    }
bobmarksie
fuente
-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ừ
fuente
Agregue una breve explicación a su respuesta.
Nikolay Mihaylov