首页 > 解决方案 > 在文本文件中查找单词并使用 Java 将它们保存到新文件中

问题描述

我正在尝试编写一个程序来查找 txt 文件中的特定单词,并将整行写入单独的文件中。现在我的程序只是重写整个文件并将其保存到新文件中。这部分对于将替换这些行的程序的其余部分是必需的,但我已经创建了。我只是Java的初学者,我无法处理它。我需要使用正则表达式吗?


import java.io.*;

public class change {

   
    public static void main(String[] args) {
        try {
            BufferedWriter bw = new BufferedWriter(
                new FileWriter("path\\file.txt"));
            BufferedReader br = new BufferedReader(
                new FileReader("path\\newfile.txt"));
            String s;
            while((s = br.readLine()) != null){
                bw.write(s + "\n");
            }
            br.close();
            bw.close();
        } catch(Exception ex){
            return;
        }
    }
}
    


标签: javaregex

解决方案


此代码存在多个问题。

可悲的异常处理

如果出现问题,此代码将获取有关您的异常的所有有用信息(至少有 4 件事:异常的类型、异常的消息、堆栈跟踪和因果链),并将其扔进垃圾箱

你会写错误。大量的 em。您对应用程序运行位置的假设将改变您。

例外对于管理这一点至关重要。

不要再写这样的代码了。修复很简单,甚至可以减少和简化您的代码!简单地堆throws Exception在你的main声明(public static void main(String[] args) throws Exception {)的末尾,并删除 try、catch 和 catch 中的 return。

这样,异常就会冒泡到任何调用main自身的地方,并且会通过打印所有各种有用的部分并退出您的应用程序来“处理”它。这就是你想要的。

字符集违规

文件是字节包,但WriterReader字符为单位。每当字节转换为字符或反之亦然时,都会应用编码。UTF-8 是一种编码。ISO-8859-1、MacRoman、CP452 等也是如此。

如果您没有看到正在应用的编码,那么通常这意味着应用了“平台默认值”,而您几乎从不想要这样。它导致代码似乎可以正常工作,直到您在其他地方或在不同的文件上运行它,然后一切都崩溃了。

解决方法是使用已融入其规范且默认为 UTF_8(例如新FilesAPI)的 API,或显式指定。顺便说一句,不幸的是FileWriterFileReader不适合目的;永远不要使用这些类,它们按设计有效地被破坏了。他们的 API 也已过时,有更新的 API。

使用旧的 API,您可以按如下方式修复它:

new BufferedWriter(new InputStreamWriter(new FileInputStream("path\\file.txt"), StandardCharsets.UTF_8));

使用新的 API 会涉及更多,见下文。

资源管理违规

当您打开资源时,您也必须明确地关闭它们。Java 是一种垃圾收集语言,但垃圾收集的“要点”是 JVM 会在它认为有必要时运行收集,而且可能需要几天时间。因此,如果您将其放置在任何地方,则任何占用的不仅仅是内存的对象都需要显式关闭。文件的“句柄”就是这样一种资源:您的操作系统提供的这些资源有限,并且一旦打开一定数量的进程,就会完全拒绝让进程打开更多文件。您的代码打开文件但可能不再关闭它们:如果发生异常,则永远不会执行该br.close()bw.close()

Java为此提供了一个工具:自动资源管理(ARM),也称为“try-with-resources”。替换这个:

BufferedWriter bw = ....;
// do stuff with the writer
bw.close();

和:

try (BufferedWriter bw = ....) {
    // do stuff with the writer
}

您使用 writer的{}标记:Java 确保无论您如何“退出”这些{}资源,资源都将被关闭。无论您只是到达此块的末尾,还是返回/中断/继续退出,或者异常导致您退出,资源都已关闭。

搜索字符串

regexps 是一种方法,但如果您正在寻找一个特定的确切字符串,那就太过分了。字符串有一个.contains()方法。

新 API

有一个新的 API。旧的 File API 有一种讨厌的倾向,即false当事情无法完成时才返回,而不是像“普通”java API 那样告诉你它。它还具有更大的灵活性:它可以处理诸如管理文件所有权、文件创建标记、访问控制和链接之类的事情。它还有一个很好的特性,即默认字符集编码(如果您不指定任何内容)是 UTF-8,而不是可怕且极其无用的“平台默认值”。

反斜杠

没有必要,即使在窗户上也是如此。path/file.txt也可以。它更容易阅读并且更常见。

var

您可以使用var而不是第二次写出可以派上用场的类型。var x = new Foo();是一样的Foo x = new Foo()

把它们放在一起

public class Change {
  public static void main(String[] args) throws Exception {
    try (
       var bw = Files.newBufferedWriter(Paths.get("path/newfile.txt"));
       var br = Files.newBufferedReader(Paths.get("path/file.txt"));
    ) {

      String s;
      while ((s = br.readLine()) != null) {
        if (s.contains("StringToFind")) {
        // or: s.matches("^.*String[a-zA-Z]WithRegexpToFind.*$")
          bw.write(s + "\n");
        }
      }
    }
  }
}

推荐阅读