方案:倒序,线性读取
实践总结:初始方案是从文件末尾开始,反方向逐个字节读取存入$buff变量,遇到换行符时将$buff写出并清空。
但是这种逐字节读取效率极低。改进方案是设置一定的缓存大小(例如2^16 => 65536),逐段地读入,判断是否有换行符,有则切割 -> reverse 并输出。
- =info
- 文本按行倒序输出
- Paktc/Vicyang
- 2019-01
- =cut
- use strict;
- use Fcntl qw(:seek);
- STDOUT->autoflush(1);
- my $src = "F:/A_Parts.txt";
- my $dst = $src;
- $dst =~s/(\.\w+)$/_REV$1/;
- reverse_write( $src, $dst );
- sub reverse_write
- {
- my ($srcfile, $dstfile) = @_;
- open my $SRC, "<:raw", $srcfile or die "$!\n";
- open my $DST, ">:raw", $dstfile or die "$!\n";
- # 缓冲区大小
- my $buffsize = 2**16;
- my $offset = -s $SRC;
- my $buff;
- my @lines;
- my $left = "";
- while ( $offset >= $buffsize )
- {
- $offset -= $buffsize;
- seek $SRC, $offset, SEEK_SET;
- read $SRC, $buff, $buffsize;
- # 拼接,考虑单行文本小于 $buffsize 的情况
- $buff = $buff . $left;
- if ( $buff =~/\r?\n/ ) {
- @lines = reverse( split /\r?\n/, $buff, -1 );
- $left = pop @lines;
- printf $DST "%s\r\n", join("\r\n", @lines);
- } else {
- $left = $buff;
- #printf "%s\n", $left;
- }
- }
- # 如果 offset 未归零,读取剩下(源文件的开头)部分
- return if ($offset <= 0);
- seek $SRC, 0, SEEK_SET;
- read $SRC, $buff, $offset;
- @lines = reverse(split /\r?\n/, $buff .$left );
- print $DST join("\r\n", @lines);
- close $SRC;
- close $DST;
- }