Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用java对大型文件进行排序_Java_Sorting - Fatal编程技术网

用java对大型文件进行排序

用java对大型文件进行排序,java,sorting,Java,Sorting,我有一个巨大的文件,每行都有独特的单词。文件大小约为1.6GB(之后我必须对15GB左右的其他文件进行排序)。到目前为止,对于较小的文件,我使用了Array.sort()。但是对于这个文件,我得到了java.lang.OutOfMemoryError:java堆空间。我知道这个错误的原因。有没有办法代替编写完整的快速排序或合并排序程序 我读到数组。sort()在内部使用快速排序或混合排序。是否有类似于Array.sort()的过程 如果我必须写一个排序程序,我应该使用哪一个?快速排序或合并排序。

我有一个巨大的文件,每行都有独特的单词。文件大小约为1.6GB(之后我必须对15GB左右的其他文件进行排序)。到目前为止,对于较小的文件,我使用了
Array.sort()
。但是对于这个文件,我得到了
java.lang.OutOfMemoryError:java堆空间
。我知道这个错误的原因。有没有办法代替编写完整的快速排序或合并排序程序

我读到数组。sort()在内部使用快速排序或混合排序。是否有类似于
Array.sort()
的过程


如果我必须写一个排序程序,我应该使用哪一个?快速排序或合并排序。我担心最坏的情况。

事实证明,您的问题是堆无法容纳如此大的数组,因此您必须忘记任何意味着在数组中加载整个文件内容的解决方案(只要您不能增加堆)


所以你面对的是流媒体。当您必须处理大于可用内存的输入源时,这是唯一(也是典型的)解决方案。我建议将文件内容流式传输到您的程序中,该程序应该通过输出到随机访问文件(trickier)或数据库来执行排序。

在文件中构建记录位置数组(索引类型),也许它可以放入内存中。每个文件记录需要一个8字节的java
long
。对数组进行排序,加载记录仅用于比较而不保留(使用
RandomAccessFile
)。排序后,使用索引指针编写新的最终文件,以按所需顺序获取记录


如果记录大小不尽相同,这也会起作用。

我会采取不同的方法

给定一个文件,比如说每行只有一个元素,我会读取第一个
n
元素。我会重复这个
m
次,这样文件中的行数是
n*m+C
,而
C
是剩余的行数

处理
整数
时,您可能希望每次读取使用大约100000个元素,而
字符串
则使用更少的元素,大约1000个。它取决于每个元素所需的数据类型和内存

从那里,我将对元素的
n
数量进行排序,并将它们写入一个具有唯一名称的临时文件中

现在,由于您已对所有文件进行了排序,因此最小的元素将位于开始处。然后,您可以迭代文件,直到处理完所有元素,找到最小的元素并将其打印到新的最终输出


这种方法将减少所需的RAM数量,而不是依赖于驱动器空间,并允许您处理任何文件大小的排序。

根据要存储的数据的结构,您可以执行许多不同的操作

对于结构良好的数据,需要按一个或多个特定字段进行排序(在这种情况下,系统工具可能没有帮助),最好使用允许排序的数据存储。考虑到MongoDB的大小不超过几个100Gbs,因此它很适合这种情况。其他NoSQL数据存储也可能很好地符合这一要求,尽管Mongo的使用和安装的简单性以及对JSON数据的支持使它成为一个非常好的候选

如果您真的想使用java方法,它会变得非常棘手。这是你在面试时问的问题,我从来不会期望有人实现代码。但是,一般的解决方案是合并排序(使用随机访问文件是一个坏主意,因为它意味着插入排序,即非最佳运行时间,考虑到文件的大小,这可能是不好的)

通过合并排序,我的意思是一次读取一个文件块,这个文件块足够小,可以放入内存中(所以它取决于您有多少RAM),对它进行排序,然后将它写回磁盘上的一个新文件。读取整个文件后,您可以开始一次合并两个块文件,只读取每个块文件的头并将(两个记录中较小的一个)写回第三个文件。对“第一代”文件执行此操作,然后继续执行第二代,直到得到一个大的排序文件为止。请注意,这基本上是一种自下而上的实现合并排序的方法,学术上的递归算法是自顶向下的方法

请注意,通过使用中间文件,可以完全避免使用中间文件。这通常基于堆/优先级队列,因此实现可能会稍微复杂一些,但它减少了所需的I/O操作数量

请看


通过仔细的设计,用java实现上述功能应该不会太困难,尽管它肯定会变得棘手。我仍然强烈推荐一种开箱即用的解决方案,如Mongo。

您可以通过在命令行中将JVM参数传递给Java来增加Java堆空间。看看这里,你可以尝试读取较小的部分,然后对它们进行排序,将它们放入临时文件中,然后通过查看每个临时文件的下一行对文件进行排序。。