在文件中查找一行并将其删除

Nar*_*rek 59 java editing file

我正在寻找一个小代码片段,它会在文件中找到一行并删除该行(不是内容而是行)但找不到.例如,我有一个文件如下:

myFile.txt:

aaa
bbb
ccc
ddd
Run Code Online (Sandbox Code Playgroud)

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

MYFILE.TXT:

aaa
ccc
ddd
Run Code Online (Sandbox Code Playgroud)

Sin*_*hot 79

此解决方案可能不是最佳或漂亮的,但它可以工作.它逐行读入输入文件,将每一行写入临时输出文件.每当遇到符合您要求的行时,它就会跳过写出来的那一行.然后重命名输出文件.我从示例中省略了错误处理,关闭读者/编写者等.我还假设您正在寻找的行中没有前导或尾随空格.根据需要更改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);
Run Code Online (Sandbox Code Playgroud)

  • 您应该在重命名之前添加writer.close().否则,编写器可能没有将最后一行或两行刷新到磁盘. (13认同)
  • 最后一行中的 `renameTo` 将失败,因为 `inputFile` 已存在。在它之前,我们应该执行`inputFile.delete();` (9认同)
  • 如果我有一个大文件并且不想"复制"它怎么办? (4认同)

Nar*_*rek 24

    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();
    }
  }
Run Code Online (Sandbox Code Playgroud)

这是我在互联网上找到的.

  • 如果抛出异常,此代码将不会关闭文件,您还需要一个finally语句. (3认同)
  • 你为什么要在每一行后冲洗?那不是很低效吗? (2认同)

Ada*_*kin 20

您想要执行以下操作:

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

(我不会写实际的代码,因为这看起来像家庭作业,但随意发布有关你遇到的具体问题的其他问题)

  • 现在,如果你也写了代码,那么你就会得到接受的答案,呃!;) (6认同)

小智 16

使用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);
Run Code Online (Sandbox Code Playgroud)

  • 在这种情况下,整个文件是否会被读入内存? (4认同)
  • 如果文件很大,则很有可能出现内存不足异常。 (2认同)

Tim*_* M. 10

因此,每当我听到有人提到他们想要过滤掉文本时,我立即想到Streams(主要是因为有一种方法filter可以根据需要调用哪种过滤器).另一个答案提到Stream在Apache commons-io库中使用s,但我认为值得展示如何在标准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);
}
Run Code Online (Sandbox Code Playgroud)

我认为那里没有太多的解释,基本上Files.lines得到Stream<String>文件filter的一行,取出我们不想要的行,然后collect将新文件的所有行放入一个List.然后Files.write,我们使用附加选项将列表写在现有文件的顶部,TRUNCATE以便替换文件的旧内容.

当然,这种方法具有将每一行加载到内存中的缺点,因为它们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);
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中没有太多改变.基本上,我们不是使用collect将文件内容收集到内存中,而是使用forEach每条线路将它通过filter发送PrintWriter到的文件立即写入文件而不是存储.我们必须将它保存到临时文件中,因为我们无法在读取现有文件的同时覆盖现有文件,因此最后,我们重命名临时文件以替换现有文件.


小智 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();
    }
Run Code Online (Sandbox Code Playgroud)