2010-10-14 30 views
35

Tengo un archivo (más específicamente, un archivo de configuración 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?Buscar y reemplazar palabras/líneas en un archivo

Aquí se muestra un ejemplo del archivo de texto que estoy tratando de trabajar con:

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 ser capaz de leer el archivo y reemplazar 'debug' con otro nivel o sustituir 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.

<?xml version="1.0" encoding="UTF-8" standalone="no"?> 
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> 
<log4j:configuration> 
    <appender class="org.apache.log4j.RollingFileAppender" name="A0"> 
     <param name="append" value="false"/> 
     <param name="File" value="C:/log/.txt"/> 
     <param name="MaxBackupIndex" value="1"/> 
     <param name="MaxFileSize" value="100KB"/> 
     <layout class="org.apache.log4j.PatternLayout"> 
      <param name="ConversionPattern" value="%-4r [%t] %-5p: %c %x - %m%n"/> 
     </layout> 
    </appender> 
    <root> 
     <level value="DEBUG"/> 
     <appender-ref ref="A0"/> 
    </root> 
</log4j:configuration> 

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

Respuesta

96

Cualquier editor de texto decente tiene una búsqueda & reemplazar la instalación que admite expresiones regulares.

Sin embargo, si usted tiene razones para reinventar la rueda en Java, que puede hacer:

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 sólo funciona para Java 7 o superior. Si usted está atascado en una de Java más, 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, tendrá que añadir el control de errores y cerrar las corrientes después de que haya terminado con ellas.

IOUtils se documenta en http://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/IOUtils.html

+0

¿Qué pasa con el cierre de FileInputStream y FileOutputStream? –

+8

Eso se deja como un ejercicio para el lector (vea la oración después de la muestra del código). – meriton

+4

Está cargando todo el archivo en la memoria, que probablemente sea seguro en este caso. Pero, ¿qué pasa con los archivos más grandes (por ejemplo, 2 GB)? Lo difícil (pero correcto de hacer) es transmitir el archivo desde el origen al destino, creo. – bvdb

1

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 alguna información adicional acerca de cuál es la diferencia entre ellos: Scanner vs. StringTokenizer vs. String.Split

0

Se puede utilizar la clase de Java Scanner para analizar las palabras de un archivo y procesarlas en su aplicación, y luego usar un BufferedWriter o FileWriter para escribir volver al 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 utilizar las bibliotecas ya disponibles para el análisis de archivos XML, que ya tienen todo esto implementado y le permitirán hacer lo que desee con facilidad.

1

Este es el tipo de cosas que normalmente haría uso de un lenguaje de script para. 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 codificación de caracteres, etc. Como siempre, depende de la complejidad de sus requisitos de búsqueda/reemplazo.

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

anterior es 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.

+0

por cierto, estaba usando "org.apache.commons.configuration.PropertiesConfiguration" para el Clase de configuración que es solo un archivo de propiedades clave/valor – joshpt

15

Después de visitar esta pregunta y señalar las preocupaciones iniciales de la solución elegida, pensé que contribuiría esta para aquellos que no usan Java 7 que usa FileUtils en lugar de IOUtils de Apache Commons. La ventaja aquí es que el readFileToString y el writeStringToFile solucionan 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); 
    }