2010-10-14 2 views
35

У меня есть файл (более конкретно, файл конфигурации 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> 

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

ответ

96

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

Однако, если у вас есть основания изобретать колесо в 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

+0

Как насчет закрытия FileInputStream & FileOutputStream? –

+8

Это остается как упражнение для читателя (см. Предложение после образца кода). – meriton

+4

Вы загружаете весь файл в память, что, вероятно, безопасно в этом случае. Но как насчет больших файлов (например, 2 ГБ)? Трудная (но правильная вещь) - это потоковая передача файла из источника в пункт назначения, который я думаю. – bvdb

1

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

Вот некоторая дополнительная информация о том, что разница между ними: Scanner vs. StringTokenizer vs. String.Split

0

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

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

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

1

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

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

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

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

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

+0

, кстати, я использовал «org.apache.commons.configuration.PropertiesConfiguration» для Класс настроек, который является только файлом свойств key/value – joshpt

15

После ознакомления с этим вопросом и с учетом первоначальных проблем выбранного решения, я решил, что внес свой вклад в использование тех, кто не использует 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's necessary for your use case! 
    throw new RuntimeException("Generating file failed", e); 
    } 
Смежные вопросы