2010-10-14 4 views
35

Ich habe eine Datei (genauer gesagt, eine Log4j-Konfigurationsdatei) und ich möchte in der Lage sein, die Datei einzulesen und bestimmte Zeilen im Code auszuwählen und sie zu ersetzen. Zum Beispiel gibt es in der Datei eine Textzeichenfolge, die das Verzeichnis angibt, in dem sie gespeichert ist, oder die Ebene des Loggers. Ich möchte in der Lage sein, diese Textzeichenfolge zu ersetzen, ohne die Datei einzulesen, in eine andere Datei zu schreiben und die Originaldatei zu löschen. Gibt es eine effizientere Möglichkeit, Texte in einer Datei mithilfe von Java zu suchen und zu ersetzen? HierSuchen und Ersetzen von Wörtern/Zeilen in einer Datei

ist ein Beispiel für die Textdatei versuche ich zu arbeiten, mit:

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 

ich mit einer anderen Ebene die Datei zu lesen und ersetzen ‚DEBUG‘ in der Lage sein wollen, oder die Datei Verzeichnisnamen ersetzen 'C: /log.txt'. Die Protokollkonfigurationsdatei wird ebenfalls in XML geschrieben. Ein Beispiel dafür ist unten aufgeführt.

<?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> 

Ich denke, es ist möglich, eine Hash-Map für diese Art der Implementierung zu verwenden?

Antwort

96

Jeder anständige Texteditor hat eine Suche & Replace-Funktion, die reguläre Ausdrücke unterstützt.

Wenn Sie jedoch Grund haben, das Rad in Java neu zu erfinden, können Sie tun:

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

Dies funktioniert nur für Java 7 oder höher. Wenn Sie auf einem älteren Java stecken geblieben sind, können Sie tun:

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

In diesem Fall müssen Sie die Fehlerbehandlung hinzuzufügen und die Ströme zu schließen, nachdem Sie mit ihnen fertig sind.

IOUtils bei http://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/IOUtils.html dokumentiert

+0

Was ist mit dem Schließen der FileInputStream & FileOutputStream? –

+8

Das ist eine Übung für den Leser (siehe den Satz nach dem Codebeispiel). – meriton

+4

Sie laden die gesamte Datei in den Speicher, was in diesem Fall wahrscheinlich sicher ist. Aber was ist mit größeren Dateien (z. B. 2 GB)? Die schwierige (aber richtige Sache) ist das Streaming der Datei von der Quelle zum Ziel, denke ich. – bvdb

1

Sie können den Scanner verwenden, um die Abschnitte zu analysieren, die Sie ändern möchten. Es gibt auch Split und StringTokenizer, die vielleicht funktionieren, aber auf der Ebene, die Sie bei Scanner arbeiten, könnte es sein, was benötigt wird.

Hier einige zusätzliche Informationen darüber, was zwischen ihnen ist der Unterschied: Scanner vs. StringTokenizer vs. String.Split

0

Sie Scanner Klasse Java verwenden können Wörter einer Datei zu analysieren und sie in Ihrer Anwendung zu verarbeiten, und dann ein BufferedWriter oder FileWriter verwenden zu schreiben Zurück zur Datei, die Änderungen übernehmen.

Ich denke, es gibt einen effizienteren Weg, um die Position des Iterators des Scanners an einem Punkt zu erhalten, um die Bearbeitung besser zu implementieren. Aber da Dateien entweder zum Lesen oder zum Schreiben geöffnet sind, bin ich mir da nicht sicher.

In jedem Fall können Sie Bibliotheken verwenden, die bereits für das Parsen von XML-Dateien zur Verfügung stehen, die alles bereits implementiert haben und Ihnen erlauben werden, leicht zu machen, was Sie wollen.

1

Dies ist die Art von Dingen, die ich normalerweise eine Skriptsprache für verwenden würde. Es ist sehr nützlich, diese Art von Transformationen sehr einfach mit etwas wie Ruby/Perl/Python ausführen zu können (fügen Sie hier Ihre bevorzugte Skriptsprache ein).

Ich würde normalerweise nicht Java dafür verwenden, da es zu schwer ist in Bezug auf Entwicklungszyklus/Typisierung usw.

Beachten Sie, dass es ratsam ist, die Datei als XML zu lesen und sie als solche zu manipulieren (die obigen Skriptsprachen haben sehr nützliche und einfache APIs für diese Art von Arbeit). Eine einfache Textsuche/-ersetzung kann Ihre Datei hinsichtlich der Zeichencodierung usw. ungültig machen. Wie immer hängt dies von der Komplexität Ihrer Such-/Ersetzungsanforderungen ab.

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

oben ist meine Implementierung von Meritons Beispiel, das für mich funktioniert. Der Dateiname ist das Verzeichnis (dh D: \ Dienstprogramme \ Einstellungen.txt). Ich bin mir nicht sicher, welcher Zeichensatz verwendet werden sollte, aber ich habe diesen Code gerade auf einem Windows XP-Computer ausgeführt, und es hat den Zweck erfüllt, ohne dass diese temporäre Datei erstellt und umbenannt wurde.

+0

Übrigens habe ich "org.apache.commons.configuration.PropertiesConfiguration" für die Settings-Klasse, die nur eine Schlüssel/Wert-Eigenschaftendatei ist – joshpt

15

Nachdem ich diese Frage und die anfänglichen Bedenken der gewählten Lösung gelesen hatte, dachte ich mir, dass ich diese für diejenigen, die nicht Java 7 verwenden, die FileUtils anstelle von IOUtils von Apache Commons verwendet. Der Vorteil hierbei ist, dass die readFileToString und die writeStringToFile das Problem des Schließens der Dateien für Sie automatisch behandeln. (writeStringToFile dokumentiert es nicht, aber Sie können die Quelle lesen). Hoffentlich vereinfacht dieses Rezept die Dinge für jeden Neuling zu diesem Problem.

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