9

我正在尝试编写一段代码,逐行读取文件并存储每一行​​,最多可存储一定数量的输入数据。除了防止吸入异常大的文件外,我还想防止最终用户作恶并将诸如数据演出之类的东西放在一行上。做$str = <FILE>仍然会读一整行,这可能会很长并且会破坏我的记忆。

fgets 让我通过让我指定在每次调用期间读取的字节数并基本上让我将一根长线分成我的最大长度来做到这一点。在 perl 中是否有类似的方法可以做到这一点?我看到了一些关于sv_gets但不知道如何使用它的东西(尽管我只是粗略的谷歌搜索)。

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

编辑我想我有些困惑。我想读取 X 行,每行的最大长度为 Y。我不想读取超过 Z 字节的总数,并且我不想一次读取所有 Z 字节。我想我可以这样做并拆分线路,但想知道是否还有其他方式。如果这是最好的方法,那么使用读取功能并进行手动解析是我最简单的选择。

谢谢。

4

5 回答 5

6

Perl 没有内置的 fget,但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。

于 2010-05-28T17:42:20.347 回答
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 本身)将在下面进行所有必要的缓冲。

于 2010-05-28T16:13:11.993 回答
3

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

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

于 2010-05-28T21:44:56.927 回答
1

使用读取函数(perlfunc read)

于 2010-05-28T15:54:19.060 回答
-2

您可以轻松实现fgets()自己。这是一个像 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语义的:

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 个字符),那么只需检查<INPUT>带有length().

于 2010-05-28T16:15:22.813 回答