Znajdź i zamień słowa / wiersze w pliku

Mam plik (dokładniej plik konfiguracyjny log4j) i chcę być w stanie odczytać w pliku i wybrać pewne linie w kodzie i zastąpić je. Na przykład w pliku znajduje się ciąg tekstu, który wskazuje katalog, w którym jest przechowywany, lub poziom rejestratora. Chcę móc zastąpić ten ciąg tekstu bez czytania w pliku, zapisywania go do innego pliku i usuwania oryginalnego pliku. Czy istnieje bardziej efektywny sposób na znalezienie i wymianę teksty w pliku za pomocą Javy?

Oto przykład pliku tekstowego, z którym próbuję pracować:

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

Chcę mieć możliwość odczytania pliku i zastąpienia 'DEBUG' innym poziomem lub zastąpienia nazwy katalogu pliku 'C:/log.txt". Plik konfiguracyjny dziennika jest również zapisany w formacie xml. Przykład tego znajduje się poniżej.

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

Myślę, że możliwe jest użycie mapy hash dla tego typu implementacji?

Author: afuzzyllama, 2010-10-14

6 answers

Każdy porządny edytor tekstu ma funkcję search&replace, która obsługuje wyrażenia regularne.

Jeśli jednak masz powód, aby odkryć koło w Javie, możesz to zrobić:

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

To działa tylko dla Javy 7 lub nowszej. Jeśli utkniesz na starszej Javie, możesz to zrobić:

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

W tym przypadku musisz dodać obsługę błędów i zamknąć strumienie po ich zakończeniu.

IOUtils jest udokumentowany na http://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/IOUtils.html

 108
Author: meriton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-19 22:21:35

Po zapoznaniu się z tym pytaniem i zwróceniu uwagi na początkowe obawy dotyczące wybranego rozwiązania, pomyślałem, że podzielę się tym dla tych, którzy nie używają Javy 7, która używa FileUtils zamiast IOUtils z Apache Commons. Zaletą jest to, że readFileToStringi writeStringToFile rozwiązują problem automatycznego zamykania plików. (writeStringToFile tego nie dokumentuje, ale można odczytać źródło). Mam nadzieję, że ten przepis upraszcza rzeczy dla każdego nowego przychodząc do tego problemu.

  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);
  }
 17
Author: ojintoad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-10 20:01:22
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();
}

Powyżej jest moja implementacja przykładu Meritona, który działa dla mnie. Nazwa pliku to katalog (np. D:\utilities\settings.txt). Nie jestem pewien, jaki zestaw znaków powinien być używany, ale uruchomiłem ten kod na komputerze z systemem Windows XP właśnie teraz i zrobił sztuczkę bez robienia tego tymczasowego tworzenia plików i zmiany nazwy rzeczy.

 3
Author: joshpt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-04 18:11:17

Możesz użyć skanera do analizy i znalezienia konkretnych sekcji, które chcesz zmodyfikować. Istnieje również Split i StringTokenizer, który może działać, ale na poziomie, na którym pracujesz, może być potrzebny.

Oto kilka dodatkowych informacji, jaka jest różnica między nimi: Scanner vs. StringTokenizer vs. String.Split

 1
Author: Ryan P.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:58

To jest coś, do czego normalnie używam języka skryptowego. Bardzo przydatna jest możliwość wykonywania tego rodzaju transformacji bardzo prosto przy użyciu czegoś takiego jak Ruby / Perl / Python(Wstaw tutaj swój ulubiony język skryptowy).

Normalnie nie używałbym do tego Javy, ponieważ jest zbyt ciężka pod względem cyklu rozwoju / pisania itp.

Zauważ, że jeśli chcesz być szczególny w manipulowaniu XML, wskazane jest, aby odczytać plik jako XML i manipulować nim jako takie (powyższe języki skryptowe mają bardzo przydatne i proste API do wykonywania tego rodzaju pracy). Proste wyszukiwanie/zamiana tekstu może unieważnić plik pod względem kodowania znaków itp. Jak zawsze, zależy to od złożoności twoich wymagań wyszukiwania / wymiany.

 1
Author: Brian Agnew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-14 19:08:00

Możesz użyć klasy Java Scanner, aby przetworzyć słowa pliku i przetworzyć je w swojej aplikacji, a następnie użyć BufferedWriter lub FileWriter, aby zapisać je do pliku, stosując zmiany.

Myślę, że istnieje bardziej efektywny sposób na uzyskanie pozycji iteratora skanera w pewnym momencie, aby lepiej zaimplementować editting. Ale ponieważ pliki są albo otwarte do czytania, albo do pisania, nie jestem pewien, co do tego.

W każdym przypadku możesz użyć bibliotek już dostępnych do analizy Pliki XML, które mają już to wszystko zaimplementowane i pozwolą Ci łatwo robić to, co chcesz.

 0
Author: Luis Miguel Serrano,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-14 17:58:02