texto - modificar archivos txt en java
¿Cómo creo una cadena Java a partir del contenido de un archivo? (30)
Utilizando JDK 8 o superior:
no se utilizan bibliotecas externas
Puede crear un nuevo objeto String a partir del contenido del archivo (utilizando clases del paquete java.nio.file
):
public String readStringFromFile(String filePath) throws IOException {
String fileContent = new String(Files.readAllBytes(Paths.get(filePath)));
return fileContent;
}
He estado usando el lenguaje de abajo desde hace algún tiempo. Y parece ser la más extendida, al menos en los sitios que he visitado.
¿Hay una 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();
}
}
Lee todo el texto de un archivo
Aquí hay un lenguaje 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, representado como una 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 se encuentra una IOException
al leer el archivo, se envuelve en una excepción UncheckedIOException
, ya que Stream
no acepta lambdas que arrojan excepciones marcadas.
try (BufferedReader r = Files.newBufferedReader(path, encoding)) {
r.lines().forEach(System.out::println);
}
También hay un método de Files.lines()
que hace algo muy similar, devolviendo el Stream<String>
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 tu 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 evitarlo como práctica para no intentar invocar el flujo accidentalmente dos veces.
Utilización de la memoria
El primer método, que conserva los saltos de línea, puede requerir temporalmente memoria varias veces el tamaño del archivo, ya que durante un breve período de tiempo el contenido sin procesar del archivo (una matriz de bytes) y los caracteres decodificados (cada uno de los cuales es de 16 bits, incluso si están codificados) como 8 bits en el archivo) residen en la memoria a la vez. Es más seguro aplicar a los 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 buffer 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 grandes, necesita un diseño diferente para su programa, uno que lea un fragmento de texto de una secuencia, lo procese y luego pase a la 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 puede ser de muchos gigabytes de RAM. El tercer método, usando un Stream<String>
es una forma de hacer esto, si sus "registros" de entrada son líneas individuales. (El uso del 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 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 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 Charset
clase Charset
:
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 utiliza un búfer de bytes asignado, impidió que el archivo que se leyó se eliminara hasta que el búfer asignado se recogiera como basura. Puede ver la versión anterior a través del enlace "editado" en esta respuesta.
Además, si su archivo está dentro de un frasco, 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 su jarra es
my.jar/com/some/thing/a.txt
Entonces quieres invocarlo así:
String myTxt = fromFileInJar("/com/com/thing/a.txt");
Basado en la respuesta de @erickson`s, puedes 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()]));
}
Commons 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 máquina virtual. El archivo siempre está cerrado.
Parámetros:
file
- el archivo para leer, no debe ser nuloDevoluciones: el contenido del archivo, nunca nulo.
Emite: -
IOException
- en caso de un error de E / SDesde: Commons IO 1.3.1
El código utilizado (indirectamente) por esa clase es:
IOUtils.java bajo la Licencia Apache 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 usado por Ritche_W.
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 de archivos simples.
Desde esta página una solución muy magra:
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 configurar el charset
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
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. En la manera más fácil de leer la moda es la siguiente:
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 una versión más reciente (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 puntos cercanos que ensucian todo. Pero eso es sobre todo una elección estilística.
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 la nueva String (byte [] Charset) para obtener una String de ella en la que pueda confiar. Los conjuntos de caracteres 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 robar su gloria. ;)
En una línea (Java 8), suponiendo que tiene un Reader:
String sMessage = String.join("/n", reader.lines().collect(Collectors.toList()));
Ese código normalizará los saltos de línea, lo que puede o no ser lo que realmente desea hacer.
Aquí hay una alternativa que no lo hace, y que es (IMO) más fácil 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();
}
}
Este utiliza 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
}
}
}
Existe una variación en 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);
}
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 mencionó Willi aus Rohr ). Sus opciones:
- Utilice una biblioteca externa.
- Copia este código en todos tus proyectos.
- Crea tu propia mini-biblioteca que contiene funciones que usas a menudo.
Su mejor apuesta es probablemente la segunda, ya que tiene las menores dependencias.
Leer un archivo como binario y convertirlo 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();
}
}
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!");
}
Reunió todas las formas posibles de leer el archivo como una 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 inicio de 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
utilizandoInputStreamReader
.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
- Formas de convertir un InputStream en una cadena
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 lista usa.
public static List<String> readLines(File file) throws IOException
Si está buscando una alternativa que no implique 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());
try (Scanner scanner = new Scanner(file)) {
while(scanner.hasNextLine()) {
fileContents.append(scanner.nextLine() + System.lineSeparator());
}
return fileContents.toString();
}
}
Si necesita un procesamiento de cadenas (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 ejemplos de JDK sample/lambda/BulkDataOperations
que se pueden descargar desde la página de descarga de Oracle Java SE 8
Otro ejemplo de liner.
String out = String.join("/n", Files.readAllLines(Paths.get("file.txt")));
Si no tiene acceso a 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);
}
Tenga en cuenta que cuando use fileInputStream.available()
el número entero devuelto no tiene que representar el tamaño real del archivo, sino la cantidad de bytes estimada que el sistema debería poder leer desde la secuencia sin bloquear IO. 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();
}
Se debe considerar que este enfoque no es adecuado para codificaciones de caracteres de múltiples bytes como UTF-8.
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, al leer desde una URL.
Usando esta biblioteca , es una línea:
String data = IO.from(new File("data.txt")).toString();
Usuario java.nio.Files
para 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);
}
Guava 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);
EDITADO 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, vea las clases Files , CharStreams , ByteSource y CharSource en el paquete com.google.common.io .
No puedo comentar otras entradas todavía, así que lo dejo aquí.
Una de las mejores respuestas aquí ( https://.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();
}
}
String content = new String(Files.readAllBytes(Paths.get("readMe.txt")), "UTF-8");
Desde java 7 puedes hacerlo de esta manera.
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 "";
}
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();
}