【问题标题】:Find a line in a file and remove it在文件中查找一行并将其删除
【发布时间】:2009-09-04 04:50:42
【问题描述】:

我正在寻找一个小代码 sn-p 它将在文件中找到一行并删除该行(不是内容而是行)但找不到。因此,例如,我在以下文件中有:

myFile.txt

aaa
bbb
ccc
ddd

需要有这样的函数:public void removeLine(String lineContent),如果我通过 removeLine("bbb"),我得到这样的文件:

myFile.txt:

aaa
ccc
ddd

【问题讨论】:

  • 您是否找到了实现这一目标的最佳方法。更快更快捷的方式
  • @AnkeshkumarJaisansaria 使用 FileChannel 可以帮助避免在 RAM 中或临时位置缓存整个有问题的文件,但需要重写需要缓存的行后面的所有字节被删除,我相信。有关使用 FileChannel 的更多详细信息,请参阅 this
  • @AnkeshkumarJaisansaria 我刚刚创建了this,它实际上删除了文件中匹配的字符串。此解决方案使用RandomAccessFile 而不是FileChannel,但仍然没有复制整个文件或将整个文件缓存到内存中的开销或挫折。

标签: java file editing


【解决方案1】:

这个解决方案可能不是最佳的或漂亮的,但它确实有效。它逐行读取输入文件,将每一行写入临时输出文件。每当遇到与您要查找的内容匹配的行时,它都会跳过写出该行。然后它重命名输出文件。我在示例中省略了错误处理、关闭读取器/写入器等。我还假设您要查找的行中没有前导或尾随空格。根据需要更改 trim() 周围的代码,以便找到匹配项。

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

【讨论】:

  • 我在网上找到了类似的东西,不过还是非常感谢!
  • 你应该在重命名之前添加一个 writer.close()。否则,作者可能没有将最后一两行刷新到磁盘。
  • 用BufferedWriter还是PrintWriter更好?
  • 如果我有一个大文件并且不想“复制”它怎么办?
  • 最后一行中的renameTo 将失败,因为inputFile 已存在。在它之前,我们应该执行inputFile.delete();
【解决方案2】:
    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();
    }
  }

这是我在网上找到的。

【讨论】:

  • 如果抛出异常,这段代码不会关闭文件,你也需要一个finally语句。
  • 为什么每行都刷新?这不是低效吗?
【解决方案3】:

您想要执行以下操作:

  • 打开旧文件进行阅读
  • 打开一个新的(临时)文件进行写入
  • 遍历旧文件中的行(可能使用BufferedReader
    • 对于每一行,检查它是否与您应该删除的内容相匹配
    • 如果匹配,则什么也不做
    • 如果不匹配,将其写入临时文件
  • 完成后,关闭这两个文件
  • 删除旧文件
  • 将临时文件重命名为原始文件的名称

(我不会写实际的代码,因为这看起来像家庭作业,但请随时就您遇到的特定问题发布其他问题)

【讨论】:

  • 现在如果你也写出代码,那么你就会得到公认的答案,呵呵! ;)
  • 任何不涉及创建临时文件的解决方案?一些会写在同一个文件中的解决方案。
  • @AniketSinha 当然。只需确保您已将文件完全读入数组/缓冲区/字符串并对其进行操作(因为您可以在全部读取后覆盖原始文件)
【解决方案4】:

使用 apache commons-io 和 Java 8 你可以使用

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

【讨论】:

  • @Tim 恐怕是这样
  • 如果文件很大,很可能会出现内存不足异常。
【解决方案5】:

所以,每当我听到有人提到他们想要过滤掉文本时,我都会立即想到去Streams(主要是因为有一个名为filter 的方法可以完全按照您的需要进行过滤)。另一个答案提到将Streams 与 Apache commons-io 库一起使用,但我认为值得展示如何在标准 Java 8 中完成此操作。这是最简单的形式:

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

我觉得这里没什么好解释的,基本上Files.lines 得到一个文件行的Stream&lt;String&gt;filter 取出我们不想要的行,然后collect 把所有将新文件的行转换为List。然后,我们使用附加选项TRUNCATE 将列表覆盖在现有文件的顶部Files.write,以便替换文件的旧内容。

当然,这种方法的缺点是将每一行都加载到内存中,因为它们在被写回之前都被存储到 List 中。如果我们想简单地修改而不存储,我们需要使用某种形式的OutputStream 在文件通过流时将每个新行写入文件,如下所示:

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

在这个例子中没有太大的改变。基本上,我们不是使用collect 将文件内容收集到内存中,而是使用forEach,这样通过filter 的每一行都会被发送到PrintWriter,以便立即写入文件而不是存储。我们必须将它保存到一个临时文件中,因为我们不能在我们仍在读取它的同时覆盖现有文件,所以最后我们重命名临时文件以替换现有文件。

【讨论】:

  • M 我正在​​尝试使用 java.nio 和 FileLock 来实现相同的功能。知道如何在写入内容之前使用 FileChannel 过滤内容
  • 很遗憾,不,我不熟悉 FileLock 和 FileChannel。
【解决方案6】:
    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();
    }

【讨论】:

    【解决方案7】:

    给你。此解决方案使用DataInputStream 扫描要替换的字符串的位置,并使用FileChannel 替换该确切位置的文本。它只替换它找到的字符串的第一次出现。此解决方案不会在某处存储整个文件的副本(RAM 或临时文件),它只是编辑它找到的文件部分。

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

    示例

    输入:ABCDEFGHIJKLMNOPQRSTUVWXYZ

    方法调用:

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

    结果文件:ABCDEFGHIJKLMNOP000TUVWXYZ

    【讨论】:

      【解决方案8】:

      这是完整的课程。在下面的文件中,“somelocation”指的是文件的实际路径。

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

      【讨论】:

        【解决方案9】:

        此解决方案逐行读取输入文件,将每一行写入 StringBuilder 变量。每当遇到与您要查找的内容匹配的行时,它都会跳过写出该行。然后它删除文件内容并放入 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();
        }
        

        【讨论】:

          【解决方案10】:

          使用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")
              }}
          }
          

          【讨论】:

            【解决方案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!");
                    }
                }
            
            }
            

            【讨论】:

              【解决方案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");
                  }
              }
              

              源代码:http://www.javadb.com/remove-a-line-from-a-text-file/

              【讨论】:

                【解决方案13】:

                此解决方案需要将 Apache Commons IO library 添加到构建路径中。它通过读取整个文件并写回每一行来工作,但前提是不包含搜索词。

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

                【讨论】:

                  【解决方案14】:

                  我重构了 Narek 必须创建的解决方案(根据我的说法),代码效率更高且更易于理解。我使用了嵌入式自动资源管理,这是 Java 中的一项最新功能,并使用了一个 Scanner 类,据我所知,它更容易理解和使用。

                  这是带有已编辑评论的代码:

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

                  【讨论】:

                    【解决方案15】:

                    试试这个:

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

                    【讨论】:

                      【解决方案16】:

                      老问题,但一种简单的方法是:

                      • 遍历文件,将每一行添加到一个新的数组列表中
                      • 遍历数组,找到匹配的String,然后调用remove方法。
                      • 再次遍历数组,将每一行打印到文件中,追加的布尔值应该为false,基本上替换了文件

                      【讨论】:

                        【解决方案17】:

                        此解决方案使用RandomAccessFile 仅缓存要删除的字符串之后的文件部分。它会扫描直到找到您要删除的String。然后它复制所有 找到的字符串之后的数据,然后将其覆盖找到的字符串,以及之后的所有内容。最后,它会截断文件大小以删除多余的数据。

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

                        用法:

                        文件内容:ABCDEFGHIJKLMNOPQRSTUVWXYZ

                        方法调用:remove("ABC", new File("Drive:/Path/File.extension"));

                        结果内容:DEFGHIJKLMNOPQRSTUVWXYZ

                        如果内存是一个问题,可以很容易地修改此解决方案以使用特定的、可指定的cacheSize 删除。这将只涉及迭代文件的其余部分以不断替换大小部分cacheSize。不管怎样,这个解决方案通常比在内存中缓存一个整个文件,或者将它复制到一个临时目录等要好得多。

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 2017-04-26
                          • 2011-10-26
                          • 2020-10-28
                          • 2012-06-20
                          • 2013-03-23
                          • 2014-05-21
                          • 2020-02-19
                          • 1970-01-01
                          相关资源
                          最近更新 更多