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

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 conveniente para leer un archivo como líneas de texto, representadas como una List . Este enfoque es “con pérdida” porque los separadores de línea se eliminan del final de cada línea.

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

En Java 8, BufferedReader agregó un nuevo método, lines() para producir un Stream . Si se encuentra una IOException al leer el archivo, se incluye en una IOException UncheckedIOException , ya que Stream no acepta lambdas que arrojen excepciones controladas.

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

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

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

La diferencia es que tienes un Stream asignado a una variable, e bash evitarlo como una práctica para que no trate de invocar accidentalmente el stream 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 deencoding 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 progtwig, 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, usar Stream es una forma de hacerlo, si sus “registros” de entrada son líneas individuales. (El método readLine() de BufferedReader es el equivalente de procedimiento de este enfoque).

Codificación de caracteres

Una cosa que falta en la muestra en la publicación original es la encoding 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.

La clase StandardCharsets 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 la clase Charset sí:

 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.

Commons FileUtils.readFileToString :

 public static String readFileToString(File file) throws IOException 

Lee el contenido de un archivo en una cadena utilizando la encoding predeterminada para la máquina virtual. 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

Desde: Commons IO 1.3.1

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

IOUtils.java bajo 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.

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

Si está buscando una alternativa que no involucre una biblioteca de terceros (por ejemplo, Commons I / O ), puede usar la clase Scanner :

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

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

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

 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 ""; } 

Si necesita un procesamiento de cadena (parallel processing) 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 

Hay más ejemplos disponibles en muestras de JDK sample/lambda/BulkDataOperations que 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"))); 

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(); } } 
 String content = new String(Files.readAllBytes(Paths.get("readMe.txt")), "UTF-8"); 

desde Java 7 puedes hacerlo de esta manera.

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 usar las líneas como una lista

 public static List readLines(File file) throws IOException 

Java intenta ser extremadamente general y flexible en todo lo que hace. Como resultado, algo que es relativamente simple en un lenguaje de scripting (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 se menciona en Willi aus Rohr ). Sus opciones:

  • Use una biblioteca externa.
  • Copie este código en todos sus proyectos.
  • Cree su propia mini biblioteca que contiene funciones que usa con frecuencia.

Su mejor apuesta es probablemente la segunda, ya que tiene la menor cantidad de dependencias.

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

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 API java.nio.file , que proporciona muchos accesos directos, por lo que las bibliotecas de terceros no siempre son necesarias para operaciones simples de archivos.

Existe una variación en el mismo tema que utiliza un bucle for, en lugar de un bucle while, para limitar el scope 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); } 

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 
 public static String slurp (final File file) throws IOException { StringBuilder result = new StringBuilder(); try { BufferedReader reader = new BufferedReader(new FileReader(file)); 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(); } 

Si no tiene acceso a los archivos, haga lo siguiente:

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

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 lee desde una URL.

Tenga en cuenta que al usar fileInputStream.available() el entero devuelto no tiene que representar el tamaño real del archivo, sino la cantidad de bytes que el sistema debería poder leer de la transmisión sin bloquear el IO. Una manera 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(); } 

Se debe considerar que este enfoque no es adecuado para codificaciones de caracteres multibyte como UTF-8.

¡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 } } } 

Puede probar la clase de escáner y archivo, algunas líneas de solución

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

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

  • Guava: Google usa 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 utilizando 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 lines = FileUtils.readLines( fileName, encoding ); return lines.stream().collect( Collectors.joining("\n") );*/ } 

  • Java 8 BufferReader utilizando 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 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 ); } 

  • BufferedReader usando 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 el 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

  • Formas de convertir un InputStream en una cadena

Después de Ctrl + F’ing después del escáner, creo que la solución del escáner también debe aparecer en la lista. De la manera más fácil de leer, dice 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 posterior (y realmente debería) considere usar try-with-resources para hacer que el código sea más fácil de leer. No más cosas de punto que ensucian todo. Pero eso es más que nada una elección estilística.

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

Mi sugerencia sería usar Archivos # readAllBytes (Ruta) para tomar todos los bytes y alimentarlos a una nueva Cadena (byte [] Charset) para obtener una Cadena de la que pueda confiar. Charsets será malo para ti durante toda tu vida, así que ten cuidado con estas cosas ahora.

Otros han dado código y otras cosas, y no quiero robarles su gloria. 😉

Usando esta biblioteca , es una línea:

 String data = IO.from(new File("data.txt")).toString(); 

Además, si su archivo está dentro de un contenedor, 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 con / por ejemplo si tu jar es

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

Entonces quieres invocarlo así:

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

En una línea (Java 8), suponiendo que tienes un lector:

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

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

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

Usando JDK 8 o superior:

no se usaron bibliotecas externas

Puede crear un nuevo objeto String a partir del contenido del archivo (usando las clases del paquete java.nio.file ):

 public String readStringFromFile(String filePath) throws IOException { String fileContent = new String(Files.readAllBytes(Paths.get(filePath))); return fileContent; } 

No puedo comentar otras entradas todavía, 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 un nuevo carácter de línea al final de la cadena, lo que puede causar algunos errores de weirds. 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(); } } 

Use el código:

 File file = new File("input.txt"); BufferedInputStream bin = new BufferedInputStream(new FileInputStream( file)); byte[] buffer = new byte[(int) file.length()]; bin.read(buffer); String fileStr = new String(buffer); 

fileStr contiene salida en String.