使用Perl有效地循环具有固定长度记录字符串的文件

时间:2017-06-01 10:25:11

标签: perl

我有一个文件,它有一个固定长度的记录,没有换行符。

示例:包含100个字符的文件,其长度记录固定为25个字符。 (共4条记录)

如何在不必将数据存储在变量中的情况下读取每条记录的文件。 (请参见下面的例子)

open my $fh, "<", "inputfile.txt" or die "can't open file\n";

my $data = <$fh>; # I would like to avoid storing the file contents in a variable

for (my $j = 0; $j < length $data; $j += 25 ) {

    my $record = substr($data, $j, 25) # Get one record
    print "$record\n";


}

第二个选项:

我也可以使用$ _来捕获数据。在消耗额外内存方面,我是否做了与上述相同的事情?

open my $fh, "<", "inputfile.txt" or die "can't open file\n";

while ( <$fh> ) {

    for (my $j = 0; $j < length $_; $j += 25 ) {

        my $record = substr($_, $j, 25) # Get one record
        print "$record\n";
    }
}

我不想将它存储在变量中的原因是因为我担心如果我处理的是非常大的文件,它会占用两倍于打开文件的空间。

我是否正确地假设我将在内存中占用两倍的空间,就像我打开文件时那样?

读取文件的最有效方法是什么,而不必消耗大量内存?

如果我的问题没有意义,请纠正我。

谢谢:)

3 个答案:

答案 0 :(得分:4)

您可以使用read从文件句柄中读取特定数量的字符

  

尝试从指定的FILEHANDLE读取数据的LENGTH字符到变量SCALAR。返回实际读取的字符数,文件末尾为0,如果有错误则返回undef(后者也设置$!)。 SCALAR将会增长或缩小,以便实际读取的最后一个字符是读取后标量的最后一个字符。

这是一个简短的例子。

while (read(\*DATA, my $record, 3)) {
    print $record, "\n";
}

__DATA__
foobarbazqrr

这将输出

foo
bar
baz
qrr

如果您一次读取整个文件(作为一行),您在内存中占用的空间将是整个文件的大小。如果文件只有两个非常长的记录,它一次只能读取一条记录的两倍。

答案 1 :(得分:4)

由于尚未提及 - 请查看$/ - 记录分隔符。

默认情况下,它是换行"\n"并且您逐行读取文件。

但是,您可以将引用设置为数值 - 它必须是引用,因此它不会处理文字字符串&#39; 25&#39;作为分隔符。

像这样:

#!/usr/bin/env perl
use strict;
use warnings;


local $/ = \25;

while ( <DATA> ) {
   print;
   print "\n-- end of record --\n";
}

__DATA__
1234567890123456
12345636734345345345q34523 3 2134234213 35r25253 25252 2524gfartw345sadgw54723wqu745ewsdf

答案 2 :(得分:2)

你的假设部分正确。将整个文件读入内存将需要与文件本身一样多的内存。例如,如果您的文件是100 MB,将其读入内存将使您的内存使用量增加100 MB。这并不意味着两次,因为只打开文件不需要100 MB。

至于逐个记录的最佳阅读方式,就是这样:

my $record_size = 25;
open my $fh, "<", "inputfile.txt" or die "can't open file\n";
while(read($fh, my $record, $record_size)) {
    print($record."\n")
}

另外,如果文件中包含除文本之外的任何内容,请考虑以二进制模式打开文件。