0

所以我有这些巨大的文本文件,每行都用一个逗号分隔的记录填充。我需要一种逐行处理文件的方法,删除符合特定条件的行。一些删除很容易,例如其中一个字段小于某个长度。最难的标准是这些行都有时间戳。许多记录是相同的,除了它们的时间戳,我必须删除所有记录,除了一个相同且在 15 秒内彼此相隔的记录。

所以我想知道其他人是否可以为此提出最佳方法。我确实想出了一个用 Java 编写的小程序来完成这项任务,使用 JodaTime 作为时间戳的东西,这使它变得非常容易。但是,我最初编写程序时遇到了 OutofMemory Heap Space 错误。我对代码进行了一些重构,大部分看起来都还可以,但我仍然相信它存在一些内存问题,因为有时程序似乎会挂断。这似乎需要的时间太长了。我不确定这是否是内存泄漏问题、糟糕的编码问题,或者完全是其他问题。是的,我尝试显着增加堆大小,但仍然遇到问题。

我会说该程序需要使用 Perl 或 Java。我也许也可以制作 python 脚本,但我对 python 并不太熟悉。正如我所说,由于 JodaTime 库,时间戳的东西在 Java 中是最简单的(对我来说)。我不确定如何在 Perl 中完成时间戳。但我愿意学习和使用最有效的方法。

我还将添加正在读取的文件,这些文件的大小差异很大,但一些大文件大约 100Mb,大约有 130 万条记录。

我的代码本质上是读入所有记录并将它们放入一个 Hashmap 中,其中键是类似记录将共享的记录中数据的特定子集。所以记录的一个子集不包括不同的时间戳。这样,您最终会得到一些具有相同数据但发生在不同时间的记录。(所以完全一样减去时间戳)。

然后,每个键的值是具有相同数据子集的所有记录的集合。然后我简单地遍历 Hashmap,获取每个集合并遍历它。我记录了第一条记录并将其时间与其他所有记录进行比较,看看它们是否在 15 秒内。如果是这样,则删除该记录。一旦该集合完成,它就会被写入一个文件,直到所有记录都完成。希望这是有道理的。

这行得通,但显然我这样做的方式太占用内存了。有人对更好的方法有任何想法吗?或者,我可以在 Perl 中执行此操作的方法实际上会很好,因为尝试将 Java 程序插入到当前实现中会导致许多其他问题。虽然也许这只是因为我的记忆问题和糟糕的编码。

最后,我不是要求别人为我编写程序。伪代码很好。虽然如果您对 Perl 有想法,我可以使用更多细节。我不确定如何在 Perl 中做的主要事情是时间比较的东西。我对 Perl 库进行了一些研究,但没有看到像 JodaTime 这样的东西(尽管我看的不多)。任何想法或建议表示赞赏。谢谢你。

4

2 回答 2

4

读取所有行并不理想,因为您需要将全部内容存储在内存中。

相反,您可以逐行阅读,写出您想要保留的记录。您可以保留之前命中的行的缓存,限制在当前程序的 15 秒内。在非常粗略的伪代码中,对于您阅读的每一行:

var line = ReadLine()
DiscardAnythingInCacheOlderThan(line.Date().Minus(15 seconds);
if (!cache.ContainsSomethingMatchingCriteria()) {
   // it's a line we want to keep
   WriteLine(line);
}

UpdateCache(line);  // make sure we store this line so we don't write it out again.

正如所指出的,这假设这些行按时间戳顺序排列。如果它们不是,那么我会使用 UNIXsort来实现它们,因为这样可以非常愉快地处理非常大的文件。

于 2013-01-11T15:42:05.477 回答
0

您可能会读取文件并仅输出要删除的行号(在单独的通道中进行排序和使用)。然后您的哈希映射可能只包含所需的最少数据加上行号。如果所需的数据与行大小相比较小,这可以节省大量内存。

于 2013-01-11T15:56:21.727 回答