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

1513

He estado usando el modismo a continuación por algún tiempo ahora. Y parece ser el más extendido, al menos en los sitios que he visitado.

¿Hay una manera 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();
    }
}
OscarRyz
fuente
77
¿Alguien puede explicarme de una manera muy simple qué pasa con el NIO? Cada vez que lo leo me pierdo en la enésima mención del canal :(
OscarRyz
77
recuerde que no se garantiza que el separador de línea en el archivo no sea necesariamente el mismo que el separador de línea del sistema.
Henrik Paul el
138
¿Podría por favor insertar un intento adecuado que finalmente cierre al lector? Alguien podría usar este ejemplo e introducir un error en su código.
Hans-Peter Störr
66
El código anterior tiene el error de agregar caracteres adicionales de línea nueva en la última línea. Debería ser algo como lo siguiente if (line = reader.readLine ())! = Null) {stringBuilder.append (line); } while (line = reader.readLine ())! = null) {stringBuilder.append (ls); stringBuilder.append (línea); }
Profundo
27
Java 7 presenta byte[] Files.readAllBytes(file);a aquellos que sugieren la solución de escáner 'de una línea': ¿no es necesario cerrarla?
Val

Respuestas:

1536

Leer todo el texto de un archivo

Java 11 agregó el método readString () para leer archivos pequeños como Stringterminadores de línea de preservación:

String content = Files.readString(path, StandardCharsets.US_ASCII);

Para las versiones entre Java 7 y 11, aquí hay un idioma compacto y robusto, 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 conveniente para leer un archivo como líneas de texto, representado como a 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);

Java 8 agregó el Files.lines()método para producir a Stream<String>. Nuevamente, este método es con pérdida porque los separadores de línea se eliminan. Si IOExceptionse encuentra un mensaje al leer el archivo, se envuelve en un UncheckedIOException, ya Streamque no acepta lambdas que arrojan excepciones marcadas.

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

Esto Streamnecesita una close()llamada; esto está mal documentado en la API, y sospecho que muchas personas ni siquiera notan que Streamtiene un close()método. Asegúrese de usar un bloque ARM como se muestra.

Si está trabajando con una fuente que no sea un archivo, puede utilizar el lines()método en su BufferedReaderlugar.

Utilización de la memoria

El primer método, que preserva los saltos de línea, puede requerir temporalmente memoria varias veces el tamaño del archivo, porque por un corto tiempo el contenido del archivo sin formato (una matriz de bytes) y los caracteres decodificados (cada uno de los cuales es 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, la lectura de líneas, suele ser más eficiente en la memoria, ya que el búfer de bytes de entrada para la decodificación no necesita contener todo el archivo. Sin embargo, todavía no es adecuado para archivos que son muy grandes en relación con la memoria disponible.

Para leer archivos grandes, 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 de muchos gigabytes de RAM. El tercer método, usar a Stream<String>es una forma de hacerlo, si los "registros" de entrada son líneas individuales. (El uso del readLine()método de BufferedReaderes el equivalente procesal 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 el valor predeterminado de la plataforma es lo que desea, pero son raros y debería poder justificar su elección.

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

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

El valor predeterminado de la plataforma está disponible desde laCharset propia clase :

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 de forma segura el código, y la respuesta anterior, que usaba un búfer de bytes mapeado, evitó que el archivo que se leía se eliminara hasta que el búfer mapeado se recogiera basura. Puede ver la versión anterior a través del enlace "editado" en esta respuesta.

erickson
fuente
3
Técnicamente hablando, es O (n) en tiempo y espacio. Cualitativamente, debido al requisito de inmutabilidad de Strings, es bastante difícil para la memoria; temporalmente hay dos copias de los datos de caracteres en la memoria, más el espacio para los bytes codificados. Suponiendo una codificación de un solo byte, requerirá (temporalmente) 5 bytes de memoria para cada carácter en el archivo. Dado que la pregunta pide específicamente una Cadena, eso es lo que muestro, pero si puede trabajar con el CharBuffer devuelto por "decodificación", el requisito de memoria es mucho menor. En cuanto al tiempo, no creo que encuentres nada más rápido en las bibliotecas principales de Java.
erickson
55
Posible error tipográfico? NIO tiene una clase Charset (no CharSet) llamada java.nio.charset.Charset. ¿Es esto lo que debería haber sido CharSet?
Jonathan Wright
31
Nota: después de ejercitar un poco ese código, descubrí que no puede eliminar el archivo de manera confiable inmediatamente después de leerlo con este método, lo que puede ser un problema en algunos casos, pero no el mío. ¿Puede estar relacionado con este problema: bugs.sun.com/bugdatabase/view_bug.do?bug_id=4715154 ? Finalmente fui con la propuesta de Jon Skeet que no sufre de este error. De todos modos, solo quería dar la información, para otras personas, por si acaso ...
Sébastien Nussbaumer
55
@ Sébastien Nussbaumer: También me topé con este problema. Es sorprendente que el error se haya marcado como "No se solucionará". Esto esencialmente significa que FileChannel#map, en general, es inutilizable.
Joonas Pulakka
44
@ Sébastien Nussbaumer: El error se ha eliminado de la base de datos Oracle / Sun Bug: "Este error no está disponible". Google almacenó en caché el sitio en almacenó webcache.googleusercontent.com/search?q=cache:bugs.sun.com/…
bobndrew
351

Si está dispuesto a usar una biblioteca externa, consulte Apache Commons IO (200KB JAR). Contiene un org.apache.commons.io.FileUtils.readFileToString()método que le permite leer un todo Fileen una Stringcon una línea de código.

Ejemplo:

import java.io.*;
import java.nio.charset.*;
import org.apache.commons.io.*;

public String readFile() throws IOException {
    File file = new File("data.txt");
    return FileUtils.readFileToString(file, StandardCharsets.UTF_8);
}
Willi aus Rohr
fuente
No encuentro ese método en la URL que proporciona.
OscarRyz
2
Está en la clase org.apache.commons.io.FileUtils
Cyrille Ka
2
También estoy usando FileUtils, pero me pregunto qué es mejor entre usar FileUtils o la respuesta nio aceptada.
Guillaume
44
@Guillaume: La pregunta más importante es si te sientes cómodo al depender de una biblioteca de terceros. Si tiene Commons IO o Guava en su proyecto, úselo (solo por simplicidad de código; de lo contrario, es probable que no haya una diferencia notable).
Jonik
183

Una solución muy magra basada en Scanner:

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

O, si desea configurar el juego de caracteres:

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

O, con un bloque de prueba con recursos , que llamará scanner.close()por usted:

try (Scanner scanner = new Scanner( new File("poem.txt"), "UTF-8" )) {
    String text = scanner.useDelimiter("\\A").next();
}

Recuerde que el Scannerconstructor puede lanzar un IOException. Y no olvides importar java.ioyjava.util .

Fuente: blog de Pat Niemeyer

Pablo Grisafi
fuente
44
\\ A funciona porque no hay "otro comienzo de archivo", por lo que de hecho lees el último token ... que también es el primero. Nunca lo intenté con \\ Z. También tenga en cuenta que puede leer cualquier cosa que sea legible, como archivos, flujos de entrada, canales ... A veces uso este código para leer desde la ventana de visualización del eclipse, cuando no estoy seguro de si estoy leyendo un archivo u otro ... Sí, classpath me confunde.
Pablo Grisafi
1
Como póster, puedo decir que realmente no sé si el archivo está bien cerrado y cuándo lo escribo ... Nunca escribo este en el código de producción, lo uso solo para pruebas o depuración.
Pablo Grisafi
2
Tiene un límite de 1024 caracteres, creo
Whimusical
20
El escáner implementa Closeable (invoca de cerca en la fuente), por lo que, si bien es elegante, en realidad no debería ser de una sola línea. El tamaño predeterminado del búfer es 1024, pero Scanner aumentará el tamaño según sea necesario (vea Scanner # makeSpace ())
earcam
8
Este falla para archivos vacíos con un java.util.NoSuchElementException.
SpaceTrucker
117
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

String content = new String(Files.readAllBytes(Paths.get("readMe.txt")), StandardCharsets.UTF_8);

desde java 7 puedes hacerlo de esta manera.

JoBⅈN
fuente
Esto debe aceptarse como respuesta: una sola línea, sin libs externas.
Cereza
Esto agregó un carácter de nueva línea al final, incluso si no estaba presente en el archivo
Stefan Haberl
79

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

private String readFile(String pathname) throws IOException {

    File file = new File(pathname);
    StringBuilder fileContents = new StringBuilder((int)file.length());        

    try (Scanner scanner = new Scanner(file)) {
        while(scanner.hasNextLine()) {
            fileContents.append(scanner.nextLine() + System.lineSeparator());
        }
        return fileContents.toString();
    }
}
Dónal
fuente
2
Creo que esta es la mejor manera. Visite java.sun.com/docs/books/tutorial/essential/io/scanning.html
Tarski el
3
El constructor de escáner que acepta una cadena no trata la cadena como el nombre de un archivo a leer, sino como el texto a escanear. Cometo ese error todo el tiempo. : - /
Alan Moore
@ Alan, buena captura. Edité la respuesta de Don ligeramente para arreglar eso (espero).
Jonik
3
fileContents.append (scanner.nextLine ()). append (lineSeparator);
prohibición de geoingeniería
1
Cambie la declaración de inicialización a Scanner scanner = new Scanner((Readable) new BufferedReader(new FileReader(file)));. De lo contrario, solo puede capturar parte del archivo.
Wei Yang
71

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

EDITAR por PiggyPiglet
Files#toString está en desuso y se debe eliminar Octobor 2019. En su lugar, use Files.asCharSource(new File(path), StandardCharsets.UTF_8).read();

EDITAR 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, consulte las clases Archivos , CharStreams , ByteSource y CharSource en el paquete com.google.common.io .

OscarRyz
fuente
Este código tiene una conversión de largo a int que podría mostrar un comportamiento loco con archivos grandes. ¿Tiene espacios adicionales y dónde cierra el flujo de entrada?
Mohamed Taher Alrefaie
@MTA: La transmisión está cerrada, tenga en cuenta el uso de Closeren CharSource . El código en la respuesta no es la fuente actual y actual de Guava.
Jonik
54
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 "";
    }
usuario590444
fuente
66
O aún más simple:new String(Files.readAllBytes(FileSystems.getDefault().getPath( filename)));
12
o new String(Files.readAllBytes(Paths.get(filename)));:-)
assafmo
1
Bien jugado, y para salvar al próximo tipo, el Google, Pathsaparentemente es 1.7+ como es FileSystems. (¡
Maldita
44
Es una pena que esta respuesta no tenga más votos. Estaba buscando la forma más rápida y sencilla de obtener un archivo de texto en una cadena. Esto es todo y si no me hubiera desplazado hacia abajo, hacia abajo y hacia abajo, lo habría perdido. El OP debe considerar aceptar esta respuesta para moverla a la cima.
Thorn
@ Thhorn Esta respuesta tiene un horrible manejo de errores. No use este método en el código de producción, o mejor: nunca.
xehpuk
51

Si necesita un procesamiento de cadena (procesamiento paralelo) Java 8 tiene la gran API 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

Hay más ejemplos disponibles en muestras JDK sample/lambda/BulkDataOperationsque se pueden descargar desde la 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")));
Andrei N
fuente
¿El .parallel () ocurre después de leer las líneas o antes de eso?
Istvan
El trabajo real comienza desde que se invoca la operación de recopilación de terminal (...). La secuencia se rellena perezosamente línea por línea. No es necesario leer todo el archivo en la memoria antes del procesamiento (por ejemplo, filtrado y mapeo).
Andrei N
recortar antes de elegir líneas no vacías?
Thorbjørn Ravn Andersen
50

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 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();
    }        
}
Jon Skeet
fuente
1
Perdóname por revivir un comentario tan antiguo, pero ¿querías pasar un objeto String llamado "archivo", o debería ser un objeto File?
Bryan Larson
28

Reunió todas las formas posibles de leer el archivo como cadena desde el disco o la red.

  • Guayaba: Google usando clases Resources,Files

    static Charset charset = com.google.common.base.Charsets.UTF_8;
    public static String guava_ServerFile( URL url ) throws IOException {
        return Resources.toString( url, charset );
    }
    public static String guava_DiskFile( File file ) throws IOException {
        return Files.toString( file, charset );
    }

  • APACHE - COMMONS IO usando las clases IOUtils, FileUtils

    static Charset encoding = org.apache.commons.io.Charsets.UTF_8;
    public static String commons_IOUtils( URL url ) throws IOException {
        java.io.InputStream in = url.openStream();
        try {
            return IOUtils.toString( in, encoding );
        } finally {
            IOUtils.closeQuietly(in);
        }
    }
    public static String commons_FileUtils( File file ) throws IOException {
        return FileUtils.readFileToString( file, encoding );
        /*List<String> lines = FileUtils.readLines( fileName, encoding );
        return lines.stream().collect( Collectors.joining("\n") );*/
    }

  • Java 8 BufferReader usando Stream API

    public static String streamURL_Buffer( URL url ) throws IOException {
        java.io.InputStream source = url.openStream();
        BufferedReader reader = new BufferedReader( new InputStreamReader( source ) );
        //List<String> lines = reader.lines().collect( Collectors.toList() );
        return reader.lines().collect( Collectors.joining( System.lineSeparator() ) );
    }
    public static String streamFile_Buffer( File file ) throws IOException {
        BufferedReader reader = new BufferedReader( new FileReader( file ) );
        return reader.lines().collect(Collectors.joining(System.lineSeparator()));
    }

  • Clase de escáner con expresiones regulares \A. que coincide con el comienzo de la entrada.

    static String charsetName = java.nio.charset.StandardCharsets.UTF_8.toString();
    public static String streamURL_Scanner( URL url ) throws IOException {
        java.io.InputStream source = url.openStream();
        Scanner scanner = new Scanner(source, charsetName).useDelimiter("\\A");
        return scanner.hasNext() ? scanner.next() : "";
    }
    public static String streamFile_Scanner( File file ) throws IOException {
        Scanner scanner = new Scanner(file, charsetName).useDelimiter("\\A");
        return scanner.hasNext() ? scanner.next() : "";
    }

  • Java 7 ( java.nio.file.Files.readAllBytes)

    public static String getDiskFile_Java7( File file ) throws IOException {
        byte[] readAllBytes = java.nio.file.Files.readAllBytes(Paths.get( file.getAbsolutePath() ));
        return new String( readAllBytes );
    }

  • BufferedReaderutilizando InputStreamReader.

    public static String getDiskFile_Lines( File file ) throws IOException {
        StringBuffer text = new StringBuffer();
        FileInputStream fileStream = new FileInputStream( file );
        BufferedReader br = new BufferedReader( new InputStreamReader( fileStream ) );
        for ( String line; (line = br.readLine()) != null; )
            text.append( line + System.lineSeparator() );
        return text.toString();
    }

Ejemplo con método principal para acceder a los métodos anteriores.

public static void main(String[] args) throws IOException {
    String fileName = "E:/parametarisation.csv";
    File file = new File( fileName );

    String fileStream = commons_FileUtils( file );
            // guava_DiskFile( file );
            // streamFile_Buffer( file );
            // getDiskFile_Java7( file );
            // getDiskFile_Lines( file );
    System.out.println( " File Over Disk : \n"+ fileStream );


    try {
        String src = "https://code.jquery.com/jquery-3.2.1.js";
        URL url = new URL( src );

        String urlStream = commons_IOUtils( url );
                // guava_ServerFile( url );
                // streamURL_Scanner( url );
                // streamURL_Buffer( url );
        System.out.println( " File Over Network : \n"+ urlStream );
    } catch (MalformedURLException e) {
        e.printStackTrace();
    }
}

@ver

Yash
fuente
26

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

Tiene el siguiente método

public static String readFileToString(File file) throws IOException

Si quieres las líneas como una lista usa

public static List<String> readLines(File file) throws IOException
Hogar en el tiempo
fuente
25

Desde JDK 11:

String file = ...
Path path = Paths.get(file);
String content = Files.readString(path);
// Or readString(path, someCharset), if you need a Charset different from UTF-8
leventov
fuente
¿Por qué, oh por qué, introducir nuevos métodos que se basan en el juego de caracteres predeterminado en 2018?
mryan
2
@mryan este método no se basa en el juego de caracteres predeterminado del sistema. Su valor predeterminado es UTF-8, eso está bien.
leventov
@leventov tienes razón! también lo hace Files.readAllLines! eso hace que la API de los archivos no sea muy consistente con los métodos más antiguos, pero es para mejor :)
mryan
17

Para leer un archivo como binario y convertir al final

public static String readFileAsString(String filePath) throws IOException {
    DataInputStream dis = new DataInputStream(new FileInputStream(filePath));
    try {
        long len = new File(filePath).length();
        if (len > Integer.MAX_VALUE) throw new IOException("File "+filePath+" too large, was "+len+" bytes.");
        byte[] bytes = new byte[(int) len];
        dis.readFully(bytes);
        return new String(bytes, "UTF-8");
    } finally {
        dis.close();
    }
}
Peter Lawrey
fuente
16

Con Java 7, esta es mi opción preferida para leer un archivo UTF-8:

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

Desde Java 7, el JDK tiene la nueva java.nio.fileAPI, que proporciona muchos accesos directos, por lo que las bibliotecas de terceros no siempre son necesarias para las operaciones de archivos simples.

Moritz Petersen
fuente
15

Java intenta ser extremadamente general y flexible en todo lo que hace. Como resultado, algo que es relativamente simple en un lenguaje de script (su código sería reemplazado por " open(file).read()" en python) es mucho más complicado. No parece haber una forma más corta de hacerlo, excepto el uso de una biblioteca externa (como mencionó Willi aus Rohr ). Sus opciones:

  • Utiliza una biblioteca externa.
  • Copie este código en todos sus proyectos.
  • Cree su propia mini biblioteca que contenga funciones que utiliza con frecuencia.

Su mejor apuesta es probablemente la segunda, ya que tiene menos dependencias.

Claudiu
fuente
44
Yeap Hace que el lenguaje de "alto nivel" tenga un significado diferente. Java es de alto nivel en comparación con C pero bajo en comparación con Python o Ruby
OscarRyz
3
De acuerdo en que Java es largo en abstracciones de alto nivel pero corto en métodos de conveniencia
Dónal
3
Es cierto que Java tiene una cantidad increíble de formas de tratar con Archivos y muchas de ellas parecen complicadas. Pero esto está bastante cerca de lo que tenemos en los idiomas de nivel superior:byte[] bytes = Files.readAllBytes(someFile.toPath());
Thorn
11

Usando JDK 8 o superior:

no se usan bibliotecas externas

Puede crear un nuevo objeto String a partir del contenido del archivo (Usar clases del java.nio.filepaquete):

public String readStringFromFile(String filePath) throws IOException {
    String fileContent = new String(Files.readAllBytes(Paths.get(filePath)));
    return fileContent;
}
Saikat
fuente
Duplicado de la respuesta de Moritz Petersen que escribió: String content = new String (Files.readAllBytes (Paths.get (filename)), "UTF-8");
Jean-Christophe Blanchard
8

Existe una variación sobre el mismo tema que utiliza un bucle for, en lugar de un bucle while, para limitar el alcance de la variable de línea. Si es "mejor" es una cuestión de gusto personal.

for(String line = reader.readLine(); line != null; line = reader.readLine()) {
    stringBuilder.append(line);
    stringBuilder.append(ls);
}
Dan Dyer
fuente
3
Esto cambiará las líneas nuevas a la elección de línea nueva predeterminada. Esto puede ser deseable o no deseado.
Peter Lawrey
Retrocedió la edición a esta respuesta porque el objetivo era reducir el alcance de la linevariable. La edición lo declaró dos veces, lo que sería un error de compilación.
Dan Dyer
7

Si no tiene acceso a la Filesclase, puede usar una solución nativa.

static String readFile(File file, String charset)
        throws IOException
{
    FileInputStream fileInputStream = new FileInputStream(file);
    byte[] buffer = new byte[fileInputStream.available()];
    int length = fileInputStream.read(buffer);
    fileInputStream.close();
    return new String(buffer, 0, length, charset);
}
Ilya Gazman
fuente
ejemplo charset para invocar?
Thufir
4

Una solución flexible que utiliza IOUtils de Apache commons-io en combinación con StringWriter :

Reader input = new FileReader();
StringWriter output = new StringWriter();
try {
  IOUtils.copy(input, output);
} finally {
  input.close();
}
String fileContents = output.toString();

Funciona con cualquier lector o flujo de entrada (no solo con archivos), por ejemplo, cuando se lee desde una URL.

wau
fuente
3

Tenga en cuenta que el uso fileInputStream.available()del número entero devuelto no tiene que representar el tamaño real del archivo, sino la cantidad adivinada de bytes que el sistema debería poder leer de la secuencia sin bloquear las E / S. Una forma segura y simple podría verse así

public String readStringFromInputStream(FileInputStream fileInputStream) {
    StringBuffer stringBuffer = new StringBuffer();
    try {
        byte[] buffer;
        while (fileInputStream.available() > 0) {
            buffer = new byte[fileInputStream.available()];
            fileInputStream.read(buffer);
            stringBuffer.append(new String(buffer, "ISO-8859-1"));
        }
    } catch (FileNotFoundException e) {
    } catch (IOException e) { }
    return stringBuffer.toString();
}

Debe considerarse que este enfoque no es adecuado para codificaciones de caracteres de varios bytes como UTF-8.

Enrique
fuente
1
Este código puede dar resultados impredecibles. De acuerdo con la documentación del available()método, no hay garantía de que se alcance el final del archivo en el caso de que el método devuelva 0. En ese caso, podría terminar con un archivo incompleto. Lo que es peor, el número de bytes realmente leídos puede ser menor que el valor devuelto available(), en cuyo caso se corrompe la salida.
wau
3

Este usa el método RandomAccessFile.readFully, ¡parece estar disponible desde JDK 1.0!

public static String readFileContent(String filename, Charset charset) throws IOException {
    RandomAccessFile raf = null;
    try {
        raf = new RandomAccessFile(filename, "r");
        byte[] buffer = new byte[(int)raf.length()];
        raf.readFully(buffer);
        return new String(buffer, charset);
    } finally {
        closeStream(raf);
    }
} 


private static void closeStream(Closeable c) {
    if (c != null) {
        try {
            c.close();
        } catch (IOException ex) {
            // do nothing
        }
    }
}
barjak
fuente
3

Puedes probar Scanner y File class, una solución de pocas líneas

 try
{
  String content = new Scanner(new File("file.txt")).useDelimiter("\\Z").next();
  System.out.println(content);
}
catch(FileNotFoundException e)
{
  System.out.println("not found!");
}
jamesjara
fuente
3

Usuario java.nio.Filespara leer todas las líneas de archivo.

public String readFile() throws IOException {
        File fileToRead = new File("file path");
        List<String> fileLines = Files.readAllLines(fileToRead.toPath());
        return StringUtils.join(fileLines, StringUtils.EMPTY);
}
Nitin Vavdiya
fuente
3
public static String slurp (final File file)
throws IOException {
    StringBuilder result = new StringBuilder();

    BufferedReader reader = new BufferedReader(new FileReader(file));

    try {
        char[] buf = new char[1024];

        int r = 0;

        while ((r = reader.read(buf)) != -1) {
            result.append(buf, 0, r);
        }
    }
    finally {
        reader.close();
    }

    return result.toString();
}
Scott S. McCoy
fuente
Creo que esto tiene el inconveniente de usar la codificación predeterminada de la plataforma. +1 de todos modos :)
OscarRyz
77
Me parece que el bloque finalmente no conoce las variables definidas en el bloque try. javac 1.6.0_21 arroja el error cannot find symbol.
ceving
¿Has probado tu propio código? Ha definido el lector en el bloque try / catch, por lo que no será accesible en el bloque finalmente.
mauron85
2

Todavía no puedo comentar otras entradas, así que lo dejaré aquí.

Una de las mejores respuestas aquí ( https://stackoverflow.com/a/326448/1521167 ):

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

Todavía tiene un defecto. Siempre pone una nueva línea de caracteres al final de la cadena, lo que puede causar algunos errores extraños. Mi sugerencia es cambiarlo a:

    private String readFile(String pathname) throws IOException {
    File file = new File(pathname);
    StringBuilder fileContents = new StringBuilder((int) file.length());
    Scanner scanner = new Scanner(new BufferedReader(new FileReader(file)));
    String lineSeparator = System.getProperty("line.separator");

    try {
        if (scanner.hasNextLine()) {
            fileContents.append(scanner.nextLine());
        }
        while (scanner.hasNextLine()) {
            fileContents.append(lineSeparator + scanner.nextLine());
        }
        return fileContents.toString();
    } finally {
        scanner.close();
    }
}
Ajk
fuente
En el primer caso, podría estar agregando una nueva línea adicional al final. en el segundo caso, podrías estar omitiendo uno. Entonces ambos están igualmente equivocados. Ver este artículo
Patrick Parker
2

Después de Ctrl + F'ing después del escáner, creo que la solución del escáner también debería aparecer en la lista. De la manera más fácil de leer, es así:

public String fileToString(File file, Charset charset) {
  Scanner fileReader = new Scanner(file, charset);
  fileReader.useDelimiter("\\Z"); // \Z means EOF.
  String out = fileReader.next();
  fileReader.close();
  return out;
}

Si usa Java 7 o más reciente (y realmente debería hacerlo), considere usar try-with-resources para que el código sea más fácil de leer. No más cosas de punto cerrado que ensucian todo. Pero eso es principalmente una elección estilística, creo.

Estoy publicando esto principalmente para completar, ya que si necesita hacer esto mucho, debería haber cosas en java.nio.file.Files que deberían hacer el trabajo mejor.

Mi sugerencia sería usar Files # readAllBytes (Path) para capturar todos los bytes y alimentarlo a una nueva cadena (byte [] Charset) para obtener una cadena en la que pueda confiar. Los charsets serán malos para ti durante tu vida, así que ten cuidado con estas cosas ahora.

Otros han dado código y esas cosas, y no quiero robarles su gloria. ;)

Haakon Løtveit
fuente
2

Usando esta biblioteca , es una línea:

String data = IO.from(new File("data.txt")).toString();
satnam
fuente
1
si no se cuentan las líneas dentro de la biblioteca.
Ari
2

Además, si su archivo está dentro de un jar, también puede usar esto:

public String fromFileInJar(String path) {
    try ( Scanner scanner 
            = new Scanner(getClass().getResourceAsStream(path))) {
        return scanner.useDelimiter("\\A").next();
    }
}

La ruta debería comenzar, / por ejemplo, si su jarra es

my.jar/com/some/thing/a.txt

Entonces quieres invocarlo así:

String myTxt = fromFileInJar("/com/com/thing/a.txt");
OscarRyz
fuente
2

En una línea (Java 8), suponiendo que tenga un Reader:

String sMessage = String.join("\n", reader.lines().collect(Collectors.toList()));
Malcolm Boekhoff
fuente
2

Según la respuesta de @ erickson, puede usar:

public String readAll(String fileName) throws IOException {
    List<String> lines = Files.readAllLines(new File(fileName).toPath());
    return String.join("\n", lines.toArray(new String[lines.size()]));
}
Muskovets
fuente