web-dev-qa-db-fra.com

Rechercher et remplacer des mots / lignes dans un fichier

J'ai un fichier (plus précisément, un fichier de configuration log4j) et je veux pouvoir le lire, choisir certaines lignes du code et les remplacer. Par exemple, une chaîne de texte dans le fichier indique le répertoire dans lequel il est stocké ou le niveau de l’enregistreur. Je veux pouvoir remplacer ces chaînes de texte sans lire le fichier, l'écrire dans un autre fichier et supprimer le fichier d'origine. Existe-t-il un moyen plus efficace de rechercher et de remplacer des textes dans un fichier en utilisant Java?

Voici un exemple de fichier texte sur lequel j'essaie de travailler:

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

Je veux pouvoir lire le fichier et remplacer "DEBUG" par un autre niveau ou remplacer le nom du répertoire de fichiers "C: /log.txt". Le fichier de configuration du journal est également écrit en XML. Un exemple de cela est présenté ci-dessous.

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

Je pense qu'il est possible d'utiliser une carte de hachage pour ce type d'implémentation?

49
user459811

Tout éditeur de texte décent a une fonction de recherche et remplacement qui prend en charge les expressions régulières.

Si toutefois vous avez raison de réinventer la roue en Java, vous pouvez faire:

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

Ceci ne fonctionne que pour Java 7 ou plus récent. Si vous êtes bloqué sur un Java plus ancien, vous pouvez faire:

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

Dans ce cas, vous devez ajouter la gestion des erreurs et fermer les flux une fois que vous avez terminé.

IOUtils est documenté à l'adresse http://commons.Apache.org/proper/commons-io/javadocs/api-release/org/Apache/commons/io/IOUtils.html

128
meriton

Après avoir consulté cette question et noté les préoccupations initiales de la solution choisie, je me suis dit que j'apporterais celle-ci à ceux qui n'utilisent pas Java 7 qui utilise FileUtils au lieu de IOUtils d'Apache Commons. L'avantage ici Est-ce que le readFileToString et le writeStringToFile gèrent le problème de la fermeture automatique des fichiers pour vous (writeStringToFile ne le documente pas, mais vous pouvez en lire le code source). Espérons que cette recette simplifie les choses pour quiconque nouveau abordant ce problème.

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

ci-dessus, ma mise en œuvre de l'exemple de Meriton qui fonctionne pour moi. Le nom du fichier est le répertoire (c'est-à-dire D:\utilities\settings.txt). Je ne suis pas sûr du jeu de caractères à utiliser, mais j'ai exécuté ce code sur une machine Windows XP) tout à l'heure et il a réussi le tour sans faire cette création de fichier temporaire et renommer des éléments.

3
joshpt

Vous voudrez peut-être utiliser Scanner pour analyser et trouver les sections spécifiques que vous souhaitez modifier. Il existe également des solutions Split et StringTokenizer qui peuvent fonctionner, mais au niveau où vous travaillez chez Scanner, vous pouvez en avoir besoin.

Voici quelques informations supplémentaires sur la différence entre elles: Scanner vs. StringTokenizer vs. String.Split

1
Ryan P.

C’est le genre de chose pour laquelle j’utiliserais normalement un langage de script. Il est très utile de pouvoir effectuer ces types de transformations très simplement en utilisant quelque chose comme Ruby/Perl/Python (insérez ici votre langage de script préféré).

Je n’utiliserais pas normalement Java pour cela car c’est trop lourd en termes de cycle de développement/typage, etc.

Notez que si vous souhaitez manipuler le XML avec précision, il est conseillé de lire le fichier en tant que XML et de le manipuler en tant que tel (les langages de script ci-dessus ont des API très utiles et simples pour effectuer ce type de travail). Une simple recherche/remplacement de texte peut invalider votre fichier en termes de codage de caractères, etc. Comme toujours, cela dépend de la complexité de vos exigences en matière de recherche/remplacement.

1
Brian Agnew

Vous pouvez utiliser la classe Scanner de Java pour analyser les mots d'un fichier et les traiter dans votre application, puis utiliser un objet BufferedWriter ou FileWriter pour réécrire dans le fichier, en appliquant la changements.

Je pense qu'il y a un moyen plus efficace de connaître la position du scanner de l'itérateur à un moment donné, afin de mieux mettre en œuvre le montage. Mais comme les fichiers sont soit ouverts à la lecture, soit à l'écriture, je ne suis pas sûr de cela.

Dans tous les cas, vous pouvez utiliser les bibliothèques déjà disponibles pour l'analyse de fichiers XML, qui ont déjà tout cela implémenté et vous permettront de faire ce que vous voulez facilement.

0