Pregunta ¿Cómo creo una cadena de Java a partir del contenido de un archivo?


He estado utilizando el modismo de abajo desde hace un tiempo. Y parece ser el más extendido, al menos en los sitios que he visitado.

¿Hay alguna forma mejor / diferente de leer un archivo en una cadena en Java?

private String readFile(String file) throws IOException {
    BufferedReader reader = new BufferedReader(new FileReader (file));
    String         line = null;
    StringBuilder  stringBuilder = new StringBuilder();
    String         ls = System.getProperty("line.separator");

    try {
        while((line = reader.readLine()) != null) {
            stringBuilder.append(line);
            stringBuilder.append(ls);
        }

        return stringBuilder.toString();
    } finally {
        reader.close();
    }
}

1210
2017-11-28 18:32


origen


Respuestas:


Leer todo el texto de un archivo

Aquí hay un modismo compacto y robusto para Java 7, envuelto en un método de utilidad:

static String readFile(String path, Charset encoding) 
  throws IOException 
{
  byte[] encoded = Files.readAllBytes(Paths.get(path));
  return new String(encoded, encoding);
}

Leer líneas de texto de un archivo

Java 7 agregó un método de conveniencia para leer un archivo como líneas de texto, representado como un List<String>. Este enfoque es "con pérdida" porque los separadores de línea se eliminan del final de cada línea.

List<String> lines = Files.readAllLines(Paths.get(path), encoding);

En Java 8, BufferedReader agregó un nuevo método, lines() para producir un Stream<String>. Si una IOException se encuentra al leer el archivo, está envuelto en un UncheckedIOException, ya que Stream no acepta lambdas que lanzan excepciones marcadas.

try (BufferedReader r = Files.newBufferedReader(path, encoding)) {
  r.lines().forEach(System.out::println);
}

También hay una Files.lines() método que hace algo muy similar, devolviendo el Stream<String> directamente. Pero no me gusta los Stream necesita un close() llamada; esto está mal documentado en la API, y sospecho que mucha gente ni siquiera se da cuenta Stream tiene un close() método. Entonces su código se vería muy similar, así:

try (Stream<String> lines = Files.lines(path, encoding)) {
  lines.forEach(System.out::println);
}

La diferencia es que tienes un Stream asignado a una variable, y trato de evitar eso como una práctica para que no trate accidentalmente de invocar la transmisión dos veces.

Utilización de la memoria

El primer método, que preserva los saltos de línea, puede requerir memoria temporalmente varias veces el tamaño del archivo, porque durante un tiempo corto el contenido del archivo sin procesar (una matriz de bytes) y los caracteres decodificados (cada uno de 16 bits incluso si está codificado como 8 bits en el archivo) residen en la memoria a la vez. Es más seguro aplicarlo a archivos que sabe que son pequeños en relación con la memoria disponible.

El segundo método, líneas de lectura, suele ser más eficiente en cuanto a la memoria, porque el búfer de bytes de entrada para la decodificación no necesita contener el archivo completo. Sin embargo, todavía no es adecuado para archivos que son muy grandes en relación con la memoria disponible.

Para leer archivos de gran tamaño, necesita un diseño diferente para su programa, uno que lea un fragmento de texto de una secuencia, lo procese y luego pase al siguiente, reutilizando el mismo bloque de memoria de tamaño fijo. Aquí, "grande" depende de las especificaciones de la computadora. Hoy en día, este umbral podría ser muchos gigabytes de RAM. El tercer método, usando un Stream<String> es una forma de hacerlo, si sus "registros" de entrada son líneas individuales. (Utilizando el readLine() método de BufferedReader es el equivalente de procedimiento a este enfoque.)

Codificación de caracteres

Una cosa que falta en la muestra en la publicación original es la codificación de caracteres. Hay algunos casos especiales en los que la plataforma predeterminada es lo que desea, pero son raros, y debe poder justificar su elección.

los StandardCharsets class define algunas constantes para las codificaciones requeridas de todos los tiempos de ejecución de Java:

String content = readFile("test.txt", StandardCharsets.UTF_8);

La plataforma predeterminada está disponible desde el Charsetclase sí mismo:

String content = readFile("test.txt", Charset.defaultCharset());

Nota: Esta respuesta reemplaza en gran medida mi versión de Java 6. La utilidad de Java 7 simplifica el código de forma segura, y la respuesta anterior, que utilizaba un búfer de bytes asignado, impedía que el archivo que se leía se borrara hasta que el búfer mapeado fuera basura. Puede ver la versión anterior a través del enlace "editado" en esta respuesta.


1251
2017-11-28 18:56



Los comunes FileUtils.readFileToString:

public static String readFileToString(File file)
                       throws IOException

Lee el contenido de un archivo en una cadena usando la codificación predeterminada   para la VM El archivo siempre está cerrado.

Parámetros:

  • file - el archivo para leer, no debe ser nulo

Devoluciones:   el contenido del archivo, nunca nulo

Lanza:    - IOException - en caso de un error de E / S

Ya que:   Commons IO 1.3.1

El código utilizado (indirectamente) por esa clase es:

IOUtils.java debajo Apache License 2.0.

public static long copyLarge(InputStream input, OutputStream output)
       throws IOException {
   byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
   long count = 0;
   int n = 0;
   while (-1 != (n = input.read(buffer))) {
       output.write(buffer, 0, n);
       count += n;
   }
   return count;
}

Es muy similar al utilizado por Ritche_W.


296
2017-11-28 18:44



De esta página una solución muy pobre:

Scanner scanner = new Scanner( new File("poem.txt") );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Put this call in a finally block

o

Scanner scanner = new Scanner( new File("poem.txt"), "UTF-8" );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Put this call in a finally block

Si quieres establecer el juego de caracteres


159
2017-09-16 20:02



Si está buscando una alternativa que no implique una biblioteca de terceros (p. E / S de Commons), puedes usar el Escáner clase:

private String readFile(String pathname) throws IOException {

    File file = new File(pathname);
    StringBuilder fileContents = new StringBuilder((int)file.length());
    Scanner scanner = new Scanner(file);
    String lineSeparator = System.getProperty("line.separator");

    try {
        while(scanner.hasNextLine()) {
            fileContents.append(scanner.nextLine() + lineSeparator);
        }
        return fileContents.toString();
    } finally {
        scanner.close();
    }
}

68
2017-11-28 19:00



Guayaba tiene un método similar al de Commons IOUtils que Willi aus Rohr mencionó:

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

// ...

String text = Files.toString(new File(path), Charsets.UTF_8);

EDIT por Oscar Reyes

Este es el código subyacente (simplificado) en la biblioteca citada:

InputStream in = new FileInputStream(file);
byte[] b  = new byte[file.length()];
int len = b.length;
int total = 0;

while (total < len) {
  int result = in.read(b, total, len - total);
  if (result == -1) {
    break;
  }
  total += result;
}

return new String( b , Charsets.UTF_8 );

Editar (por Jonik): Lo anterior no coincide con el código fuente de las versiones recientes de Guava. Para la fuente actual, mira las clases Archivos, CharStreams, ByteSource y CharSource en com.google.common.io paquete.


63
2018-04-16 14:33



import java.nio.file.Files;

.......

 String readFile(String filename) {
            File f = new File(filename);
            try {
                byte[] bytes = Files.readAllBytes(f.toPath());
                return new String(bytes,"UTF-8");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "";
    }

50
2017-10-29 08:51



Si necesita un procesamiento de cadena (procesamiento paralelo) Java 8 tiene la gran API de Stream.

String result = Files.lines(Paths.get("file.txt"))
                    .parallel() // for parallel processing 
                    .map(String::trim) // to change line   
                    .filter(line -> line.length() > 2) // to filter some lines by a predicate                        
                    .collect(Collectors.joining()); // to join lines

Más ejemplos están disponibles en muestras de JDK sample/lambda/BulkDataOperations que se puede descargar de Página de descarga de Oracle Java SE 8 

Otro ejemplo de un trazador de líneas

String out = String.join("\n", Files.readAllLines(Paths.get("file.txt")));

44
2017-11-28 19:56



Ese código normalizará los saltos de línea, que pueden o no ser lo que realmente quieres hacer.

Aquí hay una alternativa que no hace eso, y que es (IMO) más simple de entender que el código NIO (aunque todavía se usa java.nio.charset.Charset)

public static String readFile(String file, String csName)
            throws IOException {
    Charset cs = Charset.forName(csName);
    return readFile(file, cs);
}

public static String readFile(String file, Charset cs)
            throws IOException {
    // No real need to close the BufferedReader/InputStreamReader
    // as they're only wrapping the stream
    FileInputStream stream = new FileInputStream(file);
    try {
        Reader reader = new BufferedReader(new InputStreamReader(stream, cs));
        StringBuilder builder = new StringBuilder();
        char[] buffer = new char[8192];
        int read;
        while ((read = reader.read(buffer, 0, buffer.length)) > 0) {
            builder.append(buffer, 0, read);
        }
        return builder.toString();
    } finally {
        // Potential issue here: if this throws an IOException,
        // it will mask any others. Normally I'd use a utility
        // method which would log exceptions and swallow them
        stream.close();
    }        
}

44
2017-10-28 07:04



String content = new String(Files.readAllBytes(Paths.get("readMe.txt")), "UTF-8");

desde Java 7 puedes hacerlo de esta manera.


40
2017-10-17 15:34



Si es un archivo de texto, ¿por qué no usarlo? apache commons-io?

Tiene el siguiente método

public static String readFileToString(File file) throws IOException

Si quieres usar las líneas como una lista

public static List<String> readLines(File file) throws IOException

22
2017-11-28 18:52