Найти и заменить слова/строки в файле
У меня есть файл (более конкретно, файл конфигурации 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
Я хочу иметь возможность прочитать файл и заменить "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>
Я думаю, что можно использовать хэш-карту для такого типа реализации?
Ответы
Ответ 1
Любой достойный текстовый редактор имеет средство поиска и замены, поддерживающее регулярные выражения.
Если, однако, у вас есть причина изобретать колесо на 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
Ответ 2
После посещения этого вопроса и отметив первоначальные проблемы выбранного решения, я решил, что внес свой вклад в это для тех, кто не использует Java 7, который использует FileUtils вместо IOUtils из Apache Commons. Преимущество здесь в том, что 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 necessary for your use case!
throw new RuntimeException("Generating file failed", e);
}
Ответ 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();
}
выше - моя реализация примера Meriton, который работает для меня. FileName - это каталог (т.е. D:\utilities\settings.txt). Я не уверен, какой набор символов следует использовать, но я запускал этот код на компьютере под управлением Windows XP только сейчас, и он сделал трюк, не делая этого временного создания файла и переименования.
Ответ 4
Возможно, вы захотите использовать Scanner для анализа и поиска определенных разделов, которые вы хотите изменить. Там также могут работать Split и StringTokenizer, но на уровне, который вы работаете в Scanner, может оказаться необходимым.
Вот дополнительная информация о том, какая разница между ними:
Сканер против StringTokenizer против String.Split
Ответ 5
Это то, что я обычно использовал для написания сценариев. Очень полезно иметь возможность выполнять эти виды преобразований очень просто, используя что-то вроде Ruby/Perl/Python (вставьте здесь свой любимый язык сценариев).
Я обычно не использовал бы Java для этого, так как он слишком тяжелый с точки зрения цикла разработки/ввода текста и т.д.
Обратите внимание, что если вы хотите быть конкретным в управлении XML, рекомендуется читать файл как XML и манипулировать им как таковым (на вышеупомянутых языках сценариев есть очень полезные и простые API-интерфейсы для выполнения такого рода работ). Простой текстовый поиск/замена может аннулировать ваш файл с точки зрения кодировки символов и т.д. Как всегда, это зависит от сложности ваших требований поиска/замены.
Ответ 6
Вы можете использовать класс Java Scanner
для анализа слов файла и обработки их в своем приложении, а затем использовать BufferedWriter
или FileWriter
для записи обратно в файл с внесением изменений.
Я думаю, что есть более эффективный способ получить позицию итератора сканера в какой-то момент, чтобы лучше реализовать редактирование. Но поскольку файлы открыты для чтения или записи, я не уверен в этом.
В любом случае вы можете использовать уже имеющиеся библиотеки для синтаксического разбора XML файлов, которые уже все это реализованы, и позволит вам делать то, что вы хотите легко.