[Perl]按行倒序输出大体积文本文件(假设文件10G以上)

There's more than one way to do it!
https://metacpan.org http://perlmonks.org
头像
paktc
渐入佳境
渐入佳境
帖子: 59
注册时间: 2016年07月21日 20:34
拥有现金: 锁定
储蓄: 锁定
Has thanked: 7 times
Been thanked: 9 times
联系:

[Perl]按行倒序输出大体积文本文件(假设文件10G以上)

帖子 #1 paktc » 2019年01月16日 16:15

假设文件大于10G,内存1G

方案:倒序,线性读取
实践总结:初始方案是从文件末尾开始,反方向逐个字节读取存入$buff变量,遇到换行符时将$buff写出并清空。
但是这种逐字节读取效率极低。改进方案是设置一定的缓存大小(例如2^16 => 65536),逐段地读入,判断是否有换行符,有则切割 -> reverse 并输出。

Code: [全选] [展开/折叠] [Download] (BigTextFile_Reverse.pl)
  1. =info
  2.     文本按行倒序输出
  3.     Paktc/Vicyang
  4.     2019-01
  5. =cut
  6.  
  7. use strict;
  8. use Fcntl qw(:seek);
  9. STDOUT->autoflush(1);
  10. my $src = "F:/A_Parts.txt";
  11. my $dst = $src;
  12. $dst =~s/(\.\w+)$/_REV$1/;
  13.  
  14. reverse_write( $src, $dst );
  15.  
  16. sub reverse_write
  17. {
  18.     my ($srcfile, $dstfile) = @_;
  19.     open my $SRC, "<:raw", $srcfile or die "$!\n";
  20.     open my $DST, ">:raw", $dstfile or die "$!\n";
  21.  
  22.     # 缓冲区大小
  23.     my $buffsize = 2**16;
  24.     my $offset = -s $SRC;
  25.     my $buff;
  26.     my @lines;
  27.     my $left = "";
  28.     while ( $offset >= $buffsize )
  29.     {
  30.         $offset -= $buffsize;
  31.         seek $SRC, $offset, SEEK_SET;
  32.         read $SRC, $buff, $buffsize;
  33.         # 拼接,考虑单行文本小于 $buffsize 的情况
  34.         $buff = $buff . $left;
  35.         if ( $buff =~/\r?\n/ ) {
  36.             @lines = reverse( split /\r?\n/, $buff, -1 );
  37.             $left = pop @lines;
  38.             printf $DST "%s\r\n", join("\r\n", @lines);
  39.         } else {
  40.             $left = $buff;
  41.             #printf "%s\n", $left;
  42.         }
  43.     }
  44.  
  45.     # 如果 offset 未归零,读取剩下(源文件的开头)部分
  46.     return if ($offset <= 0);
  47.     seek $SRC, 0, SEEK_SET;
  48.     read $SRC, $buff, $offset;
  49.     @lines = reverse(split /\r?\n/, $buff .$left );
  50.     print $DST join("\r\n", @lines);
  51.     close $SRC;
  52.     close $DST;
  53. }

回到 “Perl”

在线用户

用户浏览此论坛: 没有注册用户 和 1 访客