在Perl中,当我从文件中读取它时,我可以限制一行的长度(比如fgets)吗?

时间:2010-05-28 15:50:44

标签: perl fgets

我正在尝试编写一段代码,逐行读取文件并存储每一行​​,最多可存储一定数量的输入数据。我想防止最终用户变得邪恶,并且除了防止吸入异常大的文件之外,还要把一些数据放在一行上。做$str = <FILE>仍然会读完整行,这可能会很长,并且会让我的记忆大打折扣。

fgets允许我通过让我在每次调用期间指定要读取的字节数来实现这一点,并且基本上让我将一条长行拆分为我的最大长度。在perl中有类似的方法吗?我看到了sv_gets的一些内容,但我不确定如何使用它(尽管我只是粗略地搜索了谷歌)。

本练习的目的是避免在读取数据后进行额外的解析/缓冲。 fgets在N个字节后或达到换行符时停止。

编辑我觉得我很困惑。我想读取X行,每行最大长度为Y.我不想读取超过Z字节的总数,我宁愿不一次读取所有Z字节。我想我可以这样做并分割线,但想知道是否还有其他方法。如果这是最好的方法,那么使用read函数和手动解析是我最容易的选择。

感谢。

5 个答案:

答案 0 :(得分:5)

Perl没有内置fgets,但是File::GetLineMaxLength实现了它。

如果您想自己动手,getc非常简单。

sub fgets {
    my($fh, $limit) = @_;

    my($char, $str);
    for(1..$limit) {
        my $char = getc $fh;
        last unless defined $char;
        $str .= $char;
        last if $char eq "\n";
    }

    return $str;
}

将每个字符连接到$str是有效的,因为Perl会机会性地重新分配。如果Perl字符串有16个字节并且你连接另一个字符,Perl会将它重新分配为32个字节(32个转到64,64到128 ......)并记住长度。接下来的15个连接不需要重新分配内存或调用strlen。

答案 1 :(得分:4)

sub heres_what_id_do($$) {
    my ($fh, $len) = @_;
    my $buf = '';

    for (my $i = 0; $i < $len; ++$i) {
        my $ch = getc $fh;
        last if !defined $ch || $ch eq "\n";
        $buf .= $ch;
    }

    return $buf;
}

不是很“Perlish”但是谁在乎呢? :)操作系统(可能还有Perl本身)将在下面进行所有必要的缓冲。

答案 2 :(得分:3)

作为练习,我在C的fgets()函数周围实现了一个包装器。它回归到Perl实现的复杂文件句柄,定义为“没有fileno的东西”来覆盖绑定的句柄和诸如此类的东西。 File::fgets现在正在转向CPAN,您可以从存储库中提取副本。

一些基本的基准测试显示它比这里的任何实现快10倍。但是,我不能说它没有bug或没有泄漏内存,我的XS技能不是那么好,但它的测试比这里的任何东西都要好。

答案 3 :(得分:1)

使用read function(perlfunc read)

答案 4 :(得分:-2)

您可以自己实施fgets()。这是一个works like C

sub fgets{my($n,$c)=($_[1],''); ($_[0])=('');
  for(;defined($c)&&$c ne "\n"&&$n>0;$n--){$_[0].=($c=getc($_[2]));}
  defined($c)&&$_[0]; }

这是PHP的semantics

sub fgets{my($n,$c,$x)=($_[1],'','');
  for(;defined($c)&&$c ne "\n"&&$n>0;$n--){$x.=($c=getc($_[0]));}
  ($x ne '')&&$x; }

如果您正在尝试实施资源限制(即尝试阻止不受信任的客户端占用您的所有内存),那么您真的不应该这样做。在调用脚本之前,使用ulimit设置这些资源限制。一个好的系统管理员无论如何都会设置资源限制,但是当程序员创建设置合理限制的启动脚本时,他们会喜欢它。

如果您在将此数据代理到另一个站点之前尝试限制输入(例如,限制SMTP输入行,因为您知道远程站点可能不支持超过511个字符),那么只需检查{}之后的行长度{1}} <INPUT>