Buscar y reemplazar palabras / líneas en un archivo

Tengo un archivo (más específicamente, un archivo de configuración de log4j) y deseo poder leer en el archivo y seleccionar ciertas líneas en el código y reemplazarlas. Por ejemplo, dentro del archivo hay una cadena de texto que indica el directorio en el que está almacenado, o el nivel del registrador. Quiero poder reemplazar esa cadena de texto sin leer el archivo, escribirlo en otro archivo y eliminar el archivo original. ¿Hay una forma más eficiente de buscar y reemplazar textos en un archivo usando Java?

Aquí hay un ejemplo del archivo de texto con el que trato de trabajar:

log4j.rootLogger=DEBUG, A0 log4j.appender.A0=org.apache.log4j.RollingFileAppender log4j.appender.A0.File=C:/log.txt log4j.appender.A0.MaxFileSize=100KB log4j.appender.A0.MaxBackupIndex=1 log4j.appender.A0.layout=org.apache.log4j.RollingFileAppender log4j.appender.A0.layout.ConversionPattern=%-4r [%t] %-5p: %c %x - %m%n 

Quiero poder leer el archivo y reemplazar ‘DEBUG’ con otro nivel o reemplazar el nombre del directorio de archivos ‘C: /log.txt’. El archivo de configuración de registro también está escrito en xml. Un ejemplo de eso se presenta a continuación.

                  

¿Estoy pensando que es posible usar un mapa hash para este tipo de implementación?

Cualquier editor de texto decente tiene una función de búsqueda y reemplazo que admite expresiones regulares.

Sin embargo, si tiene motivos para reinventar la rueda en Java, puede hacer lo siguiente:

 Path path = Paths.get("test.txt"); Charset charset = StandardCharsets.UTF_8; String content = new String(Files.readAllBytes(path), charset); content = content.replaceAll("foo", "bar"); Files.write(path, content.getBytes(charset)); 

Esto solo funciona para Java 7 o posterior. Si está atascado en un Java anterior, puede hacer:

 String content = IOUtils.toString(new FileInputStream(myfile), myencoding); content = content.replaceAll(myPattern, myReplacement); IOUtils.write(content, new FileOutputStream(myfile), myencoding); 

En este caso, deberá agregar el manejo de errores y cerrar las transmisiones después de que haya terminado con ellas.

IOUtils está documentado en http://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/IOUtils.html

Después de visitar esta pregunta y observar las inquietudes iniciales de la solución elegida, pensé que contribuiría con esta para aquellos que no usan Java 7 que usa FileUtils en lugar de IOUtils de Apache Commons. La ventaja aquí es que readFileToString y writeStringToFile manejan el problema de cerrar los archivos automáticamente. (writeStringToFile no lo documenta, pero puede leer la fuente). Esperemos que esta receta simplifique las cosas para cualquier persona nueva que llegue a este problema.

  try { String content = FileUtils.readFileToString(new File("InputFile"), "UTF-8"); content = content.replaceAll("toReplace", "replacementString"); File tempFile = new File("OutputFile"); FileUtils.writeStringToFile(tempFile, content, "UTF-8"); } catch (IOException e) { //Simple exception handling, replace with what's necessary for your use case! throw new RuntimeException("Generating file failed", e); } 
 public static void replaceFileString(String old, String new) throws IOException { String fileName = Settings.getValue("fileDirectory"); FileInputStream fis = new FileInputStream(fileName); String content = IOUtils.toString(fis, Charset.defaultCharset()); content = content.replaceAll(old, new); FileOutputStream fos = new FileOutputStream(fileName); IOUtils.write(content, new FileOutputStream(fileName), Charset.defaultCharset()); fis.close(); fos.close(); } 

arriba está mi implementación del ejemplo de Meriton que funciona para mí. El nombre de archivo es el directorio (es decir, D: \ utilities \ settings.txt). No estoy seguro de qué conjunto de caracteres se debe usar, pero ejecuté este código en una máquina con Windows XP hace un momento y funcionó sin hacer esa creación temporal de archivos y renombrar cosas.

Es posible que desee utilizar el escáner para analizar y encontrar las secciones específicas que desea modificar. También hay Split y StringTokenizer que pueden funcionar, pero al nivel que está trabajando en Scanner podría ser lo que se necesita.

Aquí hay información adicional sobre la diferencia entre ellos: Scanner vs. StringTokenizer vs. String.Split

Este es el tipo de cosas para las que normalmente usaría un lenguaje de scripting. Es muy útil tener la capacidad de realizar este tipo de transformaciones simplemente usando algo como Ruby / Perl / Python (inserte aquí su lenguaje de scripting favorito).

Normalmente no usaría Java para esto ya que es demasiado pesado en términos de ciclo de desarrollo / mecanografía, etc.

Tenga en cuenta que si quiere ser particular en la manipulación de XML, es recomendable leer el archivo como XML y manipularlo como tal (los lenguajes de script anteriores tienen API muy útiles y simples para hacer este tipo de trabajo). Una simple búsqueda / reemplazo de texto puede invalidar su archivo en términos de encoding de caracteres, etc. Como siempre, depende de la complejidad de sus requisitos de búsqueda / reemplazo.

Puede usar la clase de Scanner de Java para analizar palabras de un archivo y procesarlas en su aplicación, y luego usar un BufferedWriter o FileWriter para escribir de nuevo en el archivo, aplicando los cambios.

Creo que hay una forma más eficiente de obtener la posición del escáner del escáner en algún punto, para implementar mejor la edición. Pero como los archivos están abiertos para leer o escribir, no estoy seguro de eso.

En cualquier caso, puede usar bibliotecas ya disponibles para analizar archivos XML, que ya tienen todo esto implementado y le permitirán hacer lo que quiera con facilidad.