Найти и заменить слова / строки в файле - PullRequest
48 голосов
/ 14 октября 2010

У меня есть файл (точнее, файл конфигурации log4j), и я хочу иметь возможность читать в файле, выделять определенные строки в коде и заменять их.Например, внутри файла есть строка текста, которая указывает каталог, в котором он хранится, или уровень регистратора.Я хочу иметь возможность заменить эти строки текста без чтения в файле, записи в другой файл и удаления исходного файла.Есть ли более эффективный способ поиска и замены текстов в файле с использованием Java?

Вот пример текстового файла, с которым я пытаюсь работать:

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

Iхотите иметь возможность прочитать файл и заменить «DEBUG» другим уровнем или заменить имя директории файла «C: /log.txt».Файл конфигурации журнала также написан на xml.Пример этого приведен ниже.

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

Я думаю, что может быть возможно использовать хэш-карту для этого типа реализации?

Ответы [ 6 ]

123 голосов
/ 14 октября 2010

Любой приличный текстовый редактор имеет средство поиска и замены, которое поддерживает регулярные выражения.

Если, однако, у вас есть причина заново изобрести колесо в Java, вы можете сделать:

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

Это работает только для Java 7 или новее. Если вы застряли на более старой Java, вы можете сделать:

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

В этом случае вам нужно добавить обработку ошибок и закрыть потоки после того, как с ними покончено.

IOUtils задокументировано на http://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/IOUtils.html

18 голосов
/ 11 мая 2013

Посмотрев этот вопрос и отметив первоначальные проблемы выбранного решения, я решил, что поделюсь этим вопросом для тех, кто не использует Java 7, в которой вместо FileOtils используются Apache Commons, а не IOUtils. Преимущество здесь в том, что readFileToString и writeStringToFile решают проблему автоматического закрытия файлов для вас. (writeStringToFile не документирует это, но вы можете прочитать исходный код). Надеюсь, этот рецепт упростит задачу каждому, кто только что пришел к этой проблеме.

  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);
  }
3 голосов
/ 04 января 2013
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();
}

выше - моя реализация примера Меритона, которая работает для меня.Имя файла - это каталог (т. Е. D: \ utilities \ settings.txt).Я не уверен, какой набор символов следует использовать, но я только что запустил этот код на компьютере с Windows XP, и он добился цели без создания временных файлов и переименования.

1 голос
/ 14 октября 2010

Это та вещь, для которой я обычно использую язык сценариев. Очень полезно иметь возможность выполнять эти виды преобразований очень просто, используя что-то вроде Ruby / Perl / Python (вставьте ваш любимый язык сценариев здесь).

Обычно я бы не использовал Java для этого, так как он слишком тяжелый с точки зрения цикла разработки / набора текста и т. Д.

Обратите внимание, что если вы хотите проявлять особую осторожность при манипулировании XML, желательно прочитать файл как XML и манипулировать им как таковым (приведенные выше языки сценариев имеют очень полезные и простые API для выполнения такой работы). Простой текстовый поиск / замена может сделать файл недействительным с точки зрения кодировки символов и т. Д. Как всегда, это зависит от сложности ваших требований поиска / замены.

1 голос
/ 14 октября 2010

Возможно, вы захотите использовать сканер для анализа и поиска определенных разделов, которые вы хотите изменить.Также могут работать Split и StringTokenizer, но на том уровне, на котором вы работаете в Scanner, может быть то, что вам нужно.

Вот некоторые дополнительные сведения о том, в чем разница между ними: Сканер против StringTokenizer и String.Split

0 голосов
/ 14 октября 2010

Вы можете использовать класс Java Scanner для анализа слов файла и обработки их в вашем приложении, а затем используйте BufferedWriter или FileWriter для обратной записи в файл, применяя изменения.

Я думаю, что есть более эффективный способ получить позицию итератора сканера в какой-то момент, чтобы лучше реализовать редактирование.Но поскольку файлы либо открыты для чтения, либо для записи, я не уверен в этом.

В любом случае, вы можете использовать библиотеки, уже доступные для синтаксического анализа файлов XML, в которых все это уже реализовано ипозволит вам делать то, что вы хотите легко.

...