web-dev-qa-db-fra.com

Trouver une ligne dans un fichier et le supprimer

Je cherche un petit extrait de code qui trouvera une ligne dans le fichier et supprimera cette ligne (pas le contenu mais la ligne) mais ne pourra pas le trouver. Ainsi, par exemple, j'ai dans un fichier suivant:

myFile.txt :

aaa
bbb
ccc
ddd

Besoin d'une fonction comme celle-ci: public void removeLine(String lineContent), et si je réussis removeLine("bbb"), j'obtiens un fichier comme celui-ci:

myFile.txt:

aaa
ccc
ddd
53
Narek

Cette solution peut ne pas être optimale ou jolie, mais cela fonctionne. Il lit dans un fichier d'entrée ligne par ligne, en inscrivant chaque ligne dans un fichier de sortie temporaire. Chaque fois qu'il rencontre une ligne qui correspond à ce que vous recherchez, il ignore de l'écrire. Il renomme ensuite le fichier de sortie. J'ai omis le traitement des erreurs, la fermeture des lecteurs/rédacteurs, etc. de l'exemple. Je suppose également qu’il n’ya pas d’espace au début ou à la fin de la ligne que vous recherchez. Modifiez le code autour de trim () si nécessaire pour pouvoir trouver une correspondance.

File inputFile = new File("myFile.txt");
File tempFile = new File("myTempFile.txt");

BufferedReader reader = new BufferedReader(new FileReader(inputFile));
BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile));

String lineToRemove = "bbb";
String currentLine;

while((currentLine = reader.readLine()) != null) {
    // trim newline when comparing with lineToRemove
    String trimmedLine = currentLine.trim();
    if(trimmedLine.equals(lineToRemove)) continue;
    writer.write(currentLine + System.getProperty("line.separator"));
}
writer.close(); 
reader.close(); 
boolean successful = tempFile.renameTo(inputFile);
73
SingleShot
    public void removeLineFromFile(String file, String lineToRemove) {

    try {

      File inFile = new File(file);

      if (!inFile.isFile()) {
        System.out.println("Parameter is not an existing file");
        return;
      }

      //Construct the new file that will later be renamed to the original filename.
      File tempFile = new File(inFile.getAbsolutePath() + ".tmp");

      BufferedReader br = new BufferedReader(new FileReader(file));
      PrintWriter pw = new PrintWriter(new FileWriter(tempFile));

      String line = null;

      //Read from the original file and write to the new
      //unless content matches data to be removed.
      while ((line = br.readLine()) != null) {

        if (!line.trim().equals(lineToRemove)) {

          pw.println(line);
          pw.flush();
        }
      }
      pw.close();
      br.close();

      //Delete the original file
      if (!inFile.delete()) {
        System.out.println("Could not delete file");
        return;
      }

      //Rename the new file to the filename the original file had.
      if (!tempFile.renameTo(inFile))
        System.out.println("Could not rename file");

    }
    catch (FileNotFoundException ex) {
      ex.printStackTrace();
    }
    catch (IOException ex) {
      ex.printStackTrace();
    }
  }

J'ai trouvé cela sur Internet.

24
Narek

Vous voulez faire quelque chose comme ce qui suit:

  • Ouvre l'ancien fichier en lecture
  • Ouvrir un nouveau fichier (temporaire) en écriture
  • Parcourez les lignes de l'ancien fichier (probablement à l'aide de BufferedReader )
    • Pour chaque ligne, vérifiez si cela correspond à ce que vous êtes supposé supprimer
    • Si cela correspond, ne faites rien
    • Si cela ne correspond pas, écrivez-le dans le fichier temporaire
  • Une fois terminé, fermez les deux fichiers
  • Supprimer l'ancien fichier
  • Renommez le fichier temporaire avec le nom du fichier d'origine.

(Je n'écrirai pas le code réel, car cela ressemble à un devoir, mais n'hésitez pas à poser d'autres questions sur des éléments spécifiques qui vous posent problème) 

20
Adam Batkin

En utilisant Apache commons-io et Java 8, vous pouvez utiliser

 List<String> lines = FileUtils.readLines(file);
 List<String> updatedLines = lines.stream().filter(s -> !s.contains(searchString)).collect(Collectors.toList());
 FileUtils.writeLines(file, updatedLines, false);
15
Zeze

Donc, chaque fois que j'entends quelqu'un dire qu'il veut filtrer le texte, je pense immédiatement à aller à Streams (principalement parce qu'il existe une méthode appelée filter qui filtre exactement comme vous en avez besoin). Une autre réponse mentionne l'utilisation de Streams avec la bibliothèque Apache commons-io, mais j'ai pensé qu'il serait intéressant de montrer comment cela peut être fait en Java 8 standard. Voici le formulaire le plus simple:

public void removeLine(String lineContent) throws IOException
{
    File file = new File("myFile.txt");
    List<String> out = Files.lines(file.toPath())
                        .filter(line -> !line.contains(lineContent))
                        .collect(Collectors.toList());
    Files.write(file.toPath(), out, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
}

Je pense qu'il n'y a pas grand chose à expliquer là-dedans, Files.lines obtient un Stream<String> des lignes du fichier, filter supprime les lignes que nous ne voulons pas, puis collect place toutes les lignes du nouveau fichier dans un List. Nous écrivons ensuite la liste par-dessus le fichier existant avec Files.write, en utilisant l'option supplémentaire TRUNCATE afin de remplacer l'ancien contenu du fichier.

Bien sûr, cette approche présente l’inconvénient de charger chaque ligne en mémoire car elles sont toutes stockées dans une variable List avant d’être réécrites. Si nous voulions simplement modifier sans stocker, nous aurions besoin d'utiliser une forme de OutputStream pour écrire chaque nouvelle ligne dans un fichier lors de son passage dans le flux, comme ceci:

public void removeLine(String lineContent) throws IOException
{
    File file = new File("myFile.txt");
    File temp = new File("_temp_");
    PrintWriter out = new PrintWriter(new FileWriter(temp));
    Files.lines(file.toPath())
        .filter(line -> !line.contains(lineContent))
        .forEach(out::println);
    out.flush();
    out.close();
    temp.renameTo(file);
}

Peu de choses ont changé dans cet exemple. Fondamentalement, au lieu d’utiliser collect pour rassembler le contenu du fichier en mémoire, nous utilisons forEach de sorte que chaque ligne passant par filter soit envoyée à la PrintWriter pour être écrite immédiatement dans le fichier et non stockée. Nous devons l'enregistrer dans un fichier temporaire, car nous ne pouvons pas écraser le fichier existant en même temps que nous le lisons encore. À la fin, nous renommons le fichier temporaire pour remplacer le fichier existant.

9
Tim M.

Voici. Cette solution utilise une variable DataInputStream pour rechercher la position de la chaîne à remplacer et utilise une variable FileChannel pour remplacer le texte à cette position exacte. Il ne remplace que la première occurrence de la chaîne trouvée. Cette solution ne stocke pas une copie du fichier entier quelque part , (soit le fichier RAM, soit un fichier temporaire), elle ne fait que modifier la partie du fichier trouvée.

public static long scanForString(String text, File file) throws IOException {
    if (text.isEmpty())
        return file.exists() ? 0 : -1;
    // First of all, get a byte array off of this string:
    byte[] bytes = text.getBytes(/* StandardCharsets.your_charset */);

    // Next, search the file for the byte array.
    try (DataInputStream dis = new DataInputStream(new FileInputStream(file))) {

        List<Integer> matches = new LinkedList<>();

        for (long pos = 0; pos < file.length(); pos++) {
            byte bite = dis.readByte();

            for (int i = 0; i < matches.size(); i++) {
                Integer m = matches.get(i);
                if (bytes[m] != bite)
                    matches.remove(i--);
                else if (++m == bytes.length)
                    return pos - m + 1;
                else
                    matches.set(i, m);
            }

            if (bytes[0] == bite)
                matches.add(1);
        }
    }
    return -1;
}

public static void replaceText(String text, String replacement, File file) throws IOException {
    // Open a FileChannel with writing ability. You don't really need the read
    // ability for this specific case, but there it is in case you need it for
    // something else.
    try (FileChannel channel = FileChannel.open(file.toPath(), StandardOpenOption.WRITE, StandardOpenOption.READ)) {
        long scanForString = scanForString(text, file);
        if (scanForString == -1) {
            System.out.println("String not found.");
            return;
        }
        channel.position(scanForString);
        channel.write(ByteBuffer.wrap(replacement.getBytes(/* StandardCharsets.your_charset */)));
    }
}

Exemple

Entrée: ABCDEFGHIJKLMNOPQRSTUVWXYZ

Appel de méthode:

replaceText("QRS", "000", new File("path/to/file");

Fichier résultant: ABCDEFGHIJKLMNOP000TUVWXYZ

2
Kröw
    public static void deleteLine() throws IOException {
        RandomAccessFile file = new RandomAccessFile("me.txt", "rw");
        String delete;
        String task="";
        byte []tasking;
        while ((delete = file.readLine()) != null) {
            if (delete.startsWith("BAD")) {
                continue;
            }
            task+=delete+"\n";
        }
        System.out.println(task);
        BufferedWriter writer = new BufferedWriter(new FileWriter("me.txt"));
        writer.write(task);
        file.close();
        writer.close();
    }
2
seyed ali ziaei

Voici la classe complète. Dans le fichier ci-dessous, "emplacement" fait référence au chemin d'accès réel du fichier.

import Java.io.BufferedReader;
import Java.io.BufferedWriter;
import Java.io.File;
import Java.io.FileReader;
import Java.io.FileWriter;
import Java.io.IOException;



public class FileProcess
{


    public static void main(String[] args) throws IOException
    {
        File inputFile = new File("C://somelocation//Demographics.txt");
        File tempFile = new File("C://somelocation//Demographics_report.txt");

        BufferedReader reader = new BufferedReader(new FileReader(inputFile));
        BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile));

        String currentLine;

        while((currentLine = reader.readLine()) != null) {
            if(null!=currentLine && !currentLine.equalsIgnoreCase("BBB")){
                writer.write(currentLine + System.getProperty("line.separator"));
            }
        }
        writer.close(); 
        reader.close(); 
        boolean successful = tempFile.renameTo(inputFile);
        System.out.println(successful);
    }

}
1
Sireesh Yarlagadda
public static void deleteLine(String line, String filePath) {

    File file = new File(filePath);

    File file2 = new File(file.getParent() + "\\temp" + file.getName());
    PrintWriter pw = null;
    Scanner read = null;

    FileInputStream fis = null;
    FileOutputStream fos = null;
    FileChannel src = null;
    FileChannel dest = null;

    try {


        pw = new PrintWriter(file2);
        read = new Scanner(file);

        while (read.hasNextLine()) {

            String currline = read.nextLine();

            if (line.equalsIgnoreCase(currline)) {
                continue;
            } else {
                pw.println(currline);
            }
        }

        pw.flush();

        fis = new FileInputStream(file2);
        src = fis.getChannel();
        fos = new FileOutputStream(file);
        dest = fos.getChannel();

        dest.transferFrom(src, 0, src.size());


    } catch (IOException e) {
        e.printStackTrace();
    } finally {     
        pw.close();
        read.close();

        try {
            fis.close();
            fos.close();
            src.close();
            dest.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (file2.delete()) {
            System.out.println("File is deleted");
        } else {
            System.out.println("Error occured! File: " + file2.getName() + " is not deleted!");
        }
    }

}
0
Altair

J'ai refactoré la solution que Narek devait créer (selon moi) un code légèrement plus efficace et facile à comprendre. J'ai utilisé la gestion automatique des ressources intégrée, une fonctionnalité récente de Java, ainsi qu'une classe Scanner, plus facile à comprendre et à utiliser. 

Voici le code avec les commentaires édités:

public class RemoveLineInFile {

    private static File file;

    public static void main(String[] args) {
        //create a new File
        file = new File("hello.txt");
        //takes in String that you want to get rid off
        removeLineFromFile("Hello");
    }


    public static void removeLineFromFile(String lineToRemove) {


        //if file does not exist, a file is created

            if (!file.exists()) {
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    System.out.println("File "+file.getName()+" not created successfully");
                }
            }

            // Construct the new temporary file that will later be renamed to the original
            // filename.
            File tempFile = new File(file.getAbsolutePath() + ".tmp");

           //Two Embedded Automatic Resource Managers used
            // to effectivey handle IO Responses
          try(Scanner scanner = new Scanner(file)) {
              try (PrintWriter pw = new PrintWriter(new FileWriter(tempFile))) {

                  //a declaration of a String Line Which Will Be assigned Later
                  String line;

                  // Read from the original file and write to the new
                  // unless content matches data to be removed.
                  while (scanner.hasNextLine()) {
                      line = scanner.nextLine();
                      if (!line.trim().equals(lineToRemove)) {

                          pw.println(line);
                          pw.flush();
                      }
                  }
                  // Delete the original file
                  if (!file.delete()) {
                      System.out.println("Could not delete file");
                      return;
                  }

                  // Rename the new file to the filename the original file had.
                  if (!tempFile.renameTo(file))
                      System.out.println("Could not rename file");
              }
          }
        catch (IOException e)
        {
            System.out.println("IO Exception Occurred");
        }

    }



}
0
Siddhartha Gupta

Vieille question, mais un moyen facile est de:

  • Itérer dans un fichier en ajoutant chaque ligne à une nouvelle liste de tableaux
  • parcourez le tableau, recherchez la chaîne correspondante, puis appelez la méthode remove.
  • parcourir à nouveau tableau en imprimant chaque ligne dans le fichier
0
Enemyfish
package com.ncs.cache;

import Java.io.BufferedReader;
import Java.io.FileReader;
import Java.io.File;
import Java.io.FileWriter;
import Java.io.FileNotFoundException;
import Java.io.IOException;
import Java.io.PrintWriter;

public class FileUtil {

    public void removeLineFromFile(String file, String lineToRemove) {

        try {

            File inFile = new File(file);

            if (!inFile.isFile()) {
                System.out.println("Parameter is not an existing file");
                return;
            }

            // Construct the new file that will later be renamed to the original
            // filename.
            File tempFile = new File(inFile.getAbsolutePath() + ".tmp");

            BufferedReader br = new BufferedReader(new FileReader(file));
            PrintWriter pw = new PrintWriter(new FileWriter(tempFile));

            String line = null;

            // Read from the original file and write to the new
            // unless content matches data to be removed.
            while ((line = br.readLine()) != null) {

                if (!line.trim().equals(lineToRemove)) {

                    pw.println(line);
                    pw.flush();
                }
            }
            pw.close();
            br.close();

            // Delete the original file
            if (!inFile.delete()) {
                System.out.println("Could not delete file");
                return;
            }

            // Rename the new file to the filename the original file had.
            if (!tempFile.renameTo(inFile))
                System.out.println("Could not rename file");

        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    public static void main(String[] args) {
        FileUtil util = new FileUtil();
        util.removeLineFromFile("test.txt", "bbbbb");
    }
}

src: www.javadb.com/remove-a-line-from-a-text-file/

0
iCrazybest

Cette solution utilise RandomAccessFile pour ne mettre en cache que la partie du fichier postérieure à la chaîne à supprimer. Il analyse jusqu'à trouver le String à supprimer. Ensuite, il copie toutes les données after la chaîne trouvée, puis les écrit sur la chaîne trouvée, et tout ce qui suit. Enfin, il tronque la taille du fichier pour supprimer les données en excès.

public static long scanForString(String text, File file) throws IOException {
    if (text.isEmpty())
        return file.exists() ? 0 : -1;
    // First of all, get a byte array off of this string:
    byte[] bytes = text.getBytes(/* StandardCharsets.your_charset */);

    // Next, search the file for the byte array.
    try (DataInputStream dis = new DataInputStream(new FileInputStream(file))) {

        List<Integer> matches = new LinkedList<>();

        for (long pos = 0; pos < file.length(); pos++) {
            byte bite = dis.readByte();

            for (int i = 0; i < matches.size(); i++) {
                Integer m = matches.get(i);
                if (bytes[m] != bite)
                    matches.remove(i--);
                else if (++m == bytes.length)
                    return pos - m + 1;
                else
                    matches.set(i, m);
            }

            if (bytes[0] == bite)
                matches.add(1);
        }
    }
    return -1;
}

public static void remove(String text, File file) throws IOException {
    try (RandomAccessFile rafile = new RandomAccessFile(file, "rw");) {
        long scanForString = scanForString(text, file);
        if (scanForString == -1) {
            System.out.println("String not found.");
            return;
        }
        long remainderStartPos = scanForString + text.getBytes().length;
        rafile.seek(remainderStartPos);
        int remainderSize = (int) (rafile.length() - rafile.getFilePointer());
        byte[] bytes = new byte[remainderSize];
        rafile.read(bytes);
        rafile.seek(scanForString);

        rafile.write(bytes);
        rafile.setLength(rafile.length() - (text.length()));
    }
}

Usage:

Contenu du fichier: ABCDEFGHIJKLMNOPQRSTUVWXYZ

Appel de méthode: remove("ABC", new File("Drive:/Path/File.extension"));

Contenu résultant: DEFGHIJKLMNOPQRSTUVWXYZ

Cette solution pourrait facilement être modifiée pour être supprimée avec un certain cacheSize spécifiable, si la mémoire pose un problème. Cela impliquerait simplement d'itérer sur le reste du fichier pour remplacer continuellement des portions de taille, cacheSize. Quoi qu’il en soit, cette solution est généralement bien meilleure que la mise en cache d’un fichier entier en mémoire, ou sa copie dans un répertoire temporaire, etc.

0
Kröw

Essaye ça:

public static void main(String[] args) throws IOException {

    File file = new File("file.csv");

    CSVReader csvFileReader = new CSVReader(new FileReader(file));

    List<String[]> list = csvFileReader.readAll();

    for (int i = 0; i < list.size(); i++) {
        String[] filter = list.get(i);
        if (filter[0].equalsIgnoreCase("bbb")) {
            list.remove(i);
        }
    }
    csvFileReader.close();
    CSVWriter csvOutput = new CSVWriter(new FileWriter(file));

    csvOutput.writeAll(list);
    csvOutput.flush();

    csvOutput.close();
}
0
ahmad adawi

Cette solution lit dans un fichier d'entrée ligne par ligne, en écrivant chaque ligne dans une variable StringBuilder. Chaque fois qu'il rencontre une ligne qui correspond à ce que vous recherchez, il ignore de l'écrire. Ensuite, il supprime le contenu du fichier et place le contenu variable de StringBuilder.

public void removeLineFromFile(String lineToRemove, File f) throws FileNotFoundException, IOException{
    //Reading File Content and storing it to a StringBuilder variable ( skips lineToRemove)
    StringBuilder sb = new StringBuilder();
    try (Scanner sc = new Scanner(f)) {
        String currentLine;
        while(sc.hasNext()){
            currentLine = sc.nextLine();
            if(currentLine.equals(lineToRemove)){
                continue; //skips lineToRemove
            }
            sb.append(currentLine).append("\n");
        }
    }
    //Delete File Content
    PrintWriter pw = new PrintWriter(f);
    pw.close();

    BufferedWriter writer = new BufferedWriter(new FileWriter(f, true));
    writer.append(sb.toString());
    writer.close();
}
0
Tahero

Cette solution nécessite que la bibliothèque Apache Commons IO soit ajoutée au chemin de génération. Cela fonctionne en lisant tout le fichier et en écrivant chaque ligne, mais seulement si le terme recherché n'est pas contenu.

public static void removeLineFromFile(File targetFile, String searchTerm)
        throws IOException
{
    StringBuffer fileContents = new StringBuffer(
            FileUtils.readFileToString(targetFile));
    String[] fileContentLines = fileContents.toString().split(
            System.lineSeparator());

    emptyFile(targetFile);
    fileContents = new StringBuffer();

    for (int fileContentLinesIndex = 0; fileContentLinesIndex < fileContentLines.length; fileContentLinesIndex++)
    {
        if (fileContentLines[fileContentLinesIndex].contains(searchTerm))
        {
            continue;
        }

        fileContents.append(fileContentLines[fileContentLinesIndex] + System.lineSeparator());
    }

    FileUtils.writeStringToFile(targetFile, fileContents.toString().trim());
}

private static void emptyFile(File targetFile) throws FileNotFoundException,
        IOException
{
    RandomAccessFile randomAccessFile = new RandomAccessFile(targetFile, "rw");

    randomAccessFile.setLength(0);
    randomAccessFile.close();
}
0
BullyWiiPlaza