使用Java删除文件中的重复行

Mon*_*ter 25 java file-io text file duplicates

作为我正在进行的项目的一部分,我想清理一个我生成重复行条目的文件.然而,这些重复通常不会彼此靠近.我想出了一种在Java中这样做的方法(它基本上制作了文件的副本,然后使用嵌套的while语句将一个文件中的每一行与另一个文件中的其余部分进行比较).问题是,我生成的文件非常大而且文本很重(大约225k行文本,大约40兆).我估计我目前的流程需要63个小时!这绝对是不可接受的.

但是,我需要一个集成的解决方案.最好是Java.有任何想法吗?谢谢!

Mic*_*ers 37

嗯... 40 megs似乎足够小,你可以建立一条Set线,然后将它们全部打印出来.这比进行O(n 2)I/O工作要快得多.

它会是这样的(忽略异常):

public void stripDuplicatesFromFile(String filename) {
    BufferedReader reader = new BufferedReader(new FileReader(filename));
    Set<String> lines = new HashSet<String>(10000); // maybe should be bigger
    String line;
    while ((line = reader.readLine()) != null) {
        lines.add(line);
    }
    reader.close();
    BufferedWriter writer = new BufferedWriter(new FileWriter(filename));
    for (String unique : lines) {
        writer.write(unique);
        writer.newLine();
    }
    writer.close();
}
Run Code Online (Sandbox Code Playgroud)

如果订单很重要,您可以使用a LinkedHashSet而不是a HashSet.由于元素是通过引用存储的,因此与实际数据量相比,额外链接列表的开销应该是无关紧要的.

编辑:正如工作室Alex指出的那样,如果你不介意制作一个临时文件,你可以在阅读时简单地打印出来.这允许您使用简单HashSet而不是LinkedHashSet.但我怀疑你是否注意到像这样的I/O绑定操作的区别.

  • 是的,40 megs 不算什么,将整个内容读入内存,将其转储到哈希集以仅保留唯一行,然后将其写回磁盘。 (2认同)
  • 您可以使用#lines/0.75之类的值初始化hashset,因为HashSet会创建一个新表,并在其达到默认填充等级75%时重新运行所有内容.另一种可能性是创建HashSet,其填充率为1.0f(100%),并且大小比数据计数大一些 - >"new HashSet(300000,1.0f)".这样您就可以避免昂贵的重复. (2认同)

Wim*_*ink 15

好吧,大多数答案都有点愚蠢和缓慢,因为它涉及到一些hashset或其他任何东西添加行,然后再从那个集合中移回它.让我展示伪代码中最优的解决方案:

Create a hashset for just strings.
Open the input file.
Open the output file.
while not EOF(input)
  Read Line.
  If not(Line in hashSet)
    Add Line to hashset.
    Write Line to output.
  End If.
End While.
Free hashset.
Close input.
Close output.
Run Code Online (Sandbox Code Playgroud)

请伙计们,不要让它变得比它需要的更难.:-)甚至不打扰排序,你不需要.


Pet*_*rey 10

类似的方法

public void stripDuplicatesFromFile(String filename) {
    IOUtils.writeLines(
        new LinkedHashSet<String>(IOUtils.readLines(new FileInputStream(filename)),
        "\n", new FileOutputStream(filename + ".uniq"));
}
Run Code Online (Sandbox Code Playgroud)

  • 后一个FileInputStream实际上不应该是FileOutputStream吗?除此之外,+1为简单和"知道和使用库". (2认同)
  • 此外,值得一提的是IOUtils来自Apache Commons IO(http://commons.apache.org/io/); 对每个读者来说,这可能并不明显. (2认同)