Zoek een regel in een bestand en verwijder deze

Ik ben op zoek naar een klein codefragment dat een regel in het bestand kan vinden en die regel kan verwijderen (geen inhoud maar regel) maar ik kon het niet vinden. Dus ik heb bijvoorbeeld in een bestand het volgende:

mijnBestand.txt:

aaa
bbb
ccc
ddd

Moet een functie als deze hebben: public void removeLine(String lineContent), en als ik slaag
removeLine("bbb"), ik krijg het bestand als volgt:

mijnBestand.txt:

aaa
ccc
ddd

Antwoord 1, autoriteit 100%

Deze oplossing is misschien niet optimaal of mooi, maar het werkt. Het leest regel voor regel een invoerbestand in en schrijft elke regel naar een tijdelijk uitvoerbestand. Telkens wanneer het een regel tegenkomt die overeenkomt met wat u zoekt, slaat het deze over. Het hernoemt vervolgens het uitvoerbestand. Ik heb foutafhandeling, afsluiten van readers/writers, etc. uit het voorbeeld weggelaten. Ik neem ook aan dat er geen voorloop- of volgspatie is in de regel die u zoekt. Wijzig indien nodig de code rond trim() zodat u een overeenkomst kunt vinden.

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

Antwoord 2, autoriteit 28%

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

Dit heb ik op internet gevonden.


Antwoord 3, autoriteit 22%

U wilt zoiets als het volgende doen:

  • Open het oude bestand om te lezen
  • Open een nieuw (tijdelijk) bestand om te schrijven
  • Herhaal de regels in het oude bestand (waarschijnlijk met een BufferedReader)
    • Controleer voor elke regel of deze overeenkomt met wat u zou moeten verwijderen
    • Als het overeenkomt, niets doen
    • Als het niet overeenkomt, schrijf het dan naar het tijdelijke bestand
  • Als u klaar bent, sluit u beide bestanden
  • Verwijder het oude bestand
  • Hernoem het tijdelijke bestand naar de naam van het originele bestand

(Ik zal de eigenlijke code niet schrijven, aangezien dit op huiswerk lijkt, maar voel je vrij om andere vragen te stellen over specifieke onderdelen waar je problemen mee hebt)


Antwoord 4, autoriteit 20%

U kunt apache commons-io en Java 8 gebruiken

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

Antwoord 5, autoriteit 20%

Dus als ik iemand hoor zeggen dat ze tekst willen wegfilteren, denk ik er meteen aan om naar Streams(voornamelijk omdat er een methode is genaamd filterdie precies filtert zoals je het nodig hebt). Een ander antwoord vermeldt het gebruik van Streams met de Apache commons-io-bibliotheek, maar ik dacht dat het de moeite waard zou zijn om te laten zien hoe dit in standaard Java 8 kan worden gedaan. Hier is de eenvoudigste vorm:

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

Ik denk dat er niet teveel is om uit te leggen, in feite krijgt Files.lineseen Stream<String>van de regels van het bestand, filterverwijdert de regels die we niet willen, en collectplaatst alle regels van het nieuwe bestand in een List. Vervolgens schrijven we de lijst over het bestaande bestand met Files.write, met de extra optie TRUNCATEzodat de oude inhoud van het bestand wordt vervangen.

Natuurlijk heeft deze benadering het nadeel dat elke regel in het geheugen wordt geladen, omdat ze allemaal worden opgeslagen in een Listvoordat ze weer worden weggeschreven. Als we gewoon willen wijzigen zonder op te slaan, zouden we een vorm van OutputStreammoeten gebruiken om elke nieuwe regel naar een bestand te schrijven terwijl het door de stream gaat, zoals dit:

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

Er is niet veel veranderd in dit voorbeeld. In plaats van collectte gebruiken om de bestandsinhoud in het geheugen te verzamelen, gebruiken we forEachzodat elke regel die door het filterkomt, wordt verzonden naar de PrintWriterom onmiddellijk naar het bestand te schrijven en niet op te slaan. We moeten het opslaan in een tijdelijk bestand, omdat we het bestaande bestand niet kunnen overschrijven terwijl we er nog van aan het lezen zijn, dus aan het einde hernoemen we het tijdelijke bestand om het bestaande bestand te vervangen.


Antwoord 6, autoriteit 5%

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

Antwoord 7, autoriteit 4%

Hier ga je. Deze oplossing gebruikt een DataInputStreamom te scannen naar de positie van de string die u wilt vervangen en gebruikt een FileChannelom de tekst op die exacte positie te vervangen. Het vervangt alleen het eerste voorkomen van de string die het vindt. Deze oplossing bewaart niet ergens een kopie van het hele bestand(het RAM-geheugen of een tijdelijk bestand), maar bewerkt alleen het gedeelte van het bestand dat wordt gevonden.

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 */)));
    }
}

Voorbeeld

Invoer: ABCDEFGHIJKLMNOPQRSTUVWXYZ

Methode oproep:

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

Resulterend bestand: ABCDEFGHIJKLMNOP000TUVWXYZ


Antwoord 8

Hier is de volledige klas. In het onderstaande bestand verwijst “somelocation” naar het daadwerkelijke pad van het bestand.

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

Antwoord 9

Deze oplossing leest regel voor regel een invoerbestand in en schrijft elke regel naar een StringBuilder-variabele. Telkens wanneer het een regel tegenkomt die overeenkomt met wat u zoekt, slaat het deze over. Daarna verwijdert het de bestandsinhoud en plaatst het de StringBuilder variabele inhoud.

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

Antwoord 10

Super eenvoudige methode met Maven / Gradle + Groovy.

public void deleteConfig(String text) {
    File config = new File("/the/path/config.txt")
    def lines = config.readLines()
    lines.remove(text);
    config.write("")
    lines.each {line -> {
        config.append(line+"\n")
    }}
}

Antwoord 11

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!");
        }
    }
}

Antwoord 12

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 : http://www.javadb.com /remove-a-line-from-a-text-file/


Antwoord 13

Voor deze oplossing moet de Apache Commons IO-bibliotheekworden toegevoegd aan het bouwpad. Het werkt door het hele bestand te lezen en elke regel terug te schrijven, maar alleen als de zoekterm niet is opgenomen.

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

Antwoord 14

Ik heb de oplossing die Narek nodig had, aangepast om (volgens mij) een iets efficiëntere en gemakkelijker te begrijpen code te maken. Ik gebruikte embedded Automatic Resource Management, een recente functie in Java, en gebruikte een Scanner-klasse die volgens mij gemakkelijker te begrijpen en te gebruiken is.

Hier is de code met bewerkte opmerkingen:

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

Antwoord 15

Probeer dit:

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

Antwoord 16

Oude vraag, maar een gemakkelijke manier is om:

  • Herhaal door het bestand en voeg elke regel toe aan een nieuwe arraylijst
  • doorloop de array, zoek de overeenkomende String en roep vervolgens de verwijdermethode aan.
  • herhaal opnieuw door de array, print elke regel naar het bestand, boolean voor append zou false moeten zijn, wat in feite het bestand vervangt

Antwoord 17

Deze oplossing gebruikt een RandomAccessFileom alleen het gedeelte van het bestand dat volgt op de te verwijderen string in de cache te plaatsen. Het scant totdat het de Stringvindt die je wilt verwijderen. Dan kopieert het alle gegevens nade gevonden string, schrijft het dan over de gevonden string, en alles daarna. Ten slotte wordt de bestandsgrootte ingekort om de overtollige gegevens te verwijderen.

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

Gebruik:

Inhoud bestand: ABCDEFGHIJKLMNOPQRSTUVWXYZ

Methodeaanroep: remove("ABC", new File("Drive:/Path/File.extension"));

Resulterende inhoud: DEFGHIJKLMNOPQRSTUVWXYZ

Deze oplossing kan gemakkelijk worden aangepast om te worden verwijderd met een bepaalde, gespecificeerde cacheSize, als geheugen een probleem is. Dit zou gewoon het herhalen van de rest van het bestand inhouden om voortdurend delen van de grootte, cacheSize, te vervangen. Hoe dan ook, deze oplossing is over het algemeen veel beter dan het in cache plaatsen van een volledigbestand in het geheugen, of het kopiëren naar een tijdelijke map, enz.

Other episodes