如何在perl中将文件加载到内存中

时间:2016-08-30 11:50:42

标签: perl sorting memory mmap

我尝试使用某些脚本按降序对输入文本文件进行排序,并仅打印最常用的客户。

输入文本文件包含:

  NAME,USAGE,IP
  example :
  Abc,556,10.2.3.5
  bbc,126,14.2.5.6

等等,这是一个非常大的文件,我试图避免将文件加载到内存中。

我尝试过以下脚本。

use warnings ;

use strict;

my %hash = ();
my $file = $ARGV[0] ;


open (my $fh, "<", $file) or die "Can't open the file $file: ";

while (my $line =<$fh>) 
{
chomp ($line) ;
my( $name,$key,$ip) = split /,/, $line;

$hash{$key} = [ $name, $ip ];
}

my $count= 0 ;

foreach ( sort { $b <=> $a } keys %hash ){
my $value = $hash{$_};
print "$_  @{$value} \n" ;
last if (++$count == 5);
} 

应根据使用情况对输出进行排序,并显示相应用途的名称和IP。 “`

3 个答案:

答案 0 :(得分:3)

我认为您要打印第二列中值最高的文件的五行

这可以通过一种插入排序来完成,该插入排序检查文件的每一行以查看它是否高于最近找到的五行中的最低行,但是更容易累积一个合理的子集数据的排序,排序,并丢弃除前五名之外的所有数据

这里,我有数组@top包含文件中的行。当数组中有100行时,它将被排序并减少为五个最大条目。然后,while循环继续向文件添加行,直到它再次达到限制或者在重复该过程时已到达文件的末尾。这样,文件中不超过100行在内存中有帮助

我已经生成了一个1,000行的数据文件,在第2列中使用100到2,000之间的随机值对其进行测试。下面的输出是结果

use strict;
use warnings 'all';

open my $fh, '<', 'usage.txt' or die $!;

my @top;

while ( <$fh> ) {

    push @top, $_;

    if ( @top >= 100 or eof ) {

        @top = sort {
            my ($aa, $bb) = map { (split /,/)[1] } ($a, $b);
            $bb <=> $aa;
        } @top;

        @top = @top[0..4];
    }
}

print @top;

输出

qcmmt,2000,10.2.3.5
ciumt,1999,10.2.3.5
eweae,1998,10.2.3.5
gvhwv,1998,10.2.3.5
wonmd,1993,10.2.3.5

答案 1 :(得分:2)

执行此操作的标准方法是创建包含k项的优先级队列,其中k是要返回的项目数。因此,如果您想要具有最高值的五行,您可以执行以下操作:

pq = new priority_queue
add the first five items in the file to the priority queue
for each remaining line in the file
    if value > lowest value on pq
        remove lowest value on the pq
        add new value to pq

完成文件后,pq将包含五个值最高的项目。

要在Perl中执行此操作,请使用Heap::Priority模块。

这比其他建议更快,使用更少的内存。

答案 2 :(得分:1)

记住最后5个最大行的算法。

对于每一行,请检查最低记忆元素。如果更多 - 存储在阵列中的第二个最大项目之前,具有不合等的最低值。

use warnings;
use strict;

my $file = $ARGV[0] ;
my @keys=(0,0,0,0,0);
my @res;

open (my $fh, "<", $file) or die "Can't open the file $file: ";
while(<$fh>)
{
 my($name,$key,$ip) = split /,/;
 next if($key<$keys[0]);
 for(0..4) {
  if($_==4 || $key<$keys[$_+1]) {
   @keys[0..$_-1]=@keys[1..$_] if($_>0);
   $keys[$_]=$key;
   $res[$_]=[ $name, $ip ];
   last;
  } 
 }
}
for(0..4) {
  print "$keys[4-$_]  @{$res[4-$_]}";
}

从1M随机行(20 MB)中测试文件:

Last items (This algorithm):
Start 1472567980.91183
End   1472567981.94729 (duration 1.03546 seconds)

full sort in memory (Algorithm of @Rishi):
Start 1472568441.00438
End   1472568443.43829 (duration 2.43391 seconds)

sort by parts of 100 rows (Algorithm of @Borodin):
Start 1472568185.21896
End   1472568195.59322 (duration 10.37426 seconds)