9

ファイルを1行ずつ読み取り、一定量の入力データまで各行を格納するコードを作成しようとしています。異常に大きなファイルを吸い込むのを防ぐだけでなく、エンドユーザーが悪意を持って1行にデータのギグのようなものを置くのを防ぎたいです。やる$str = <FILE>ことはまだ全行を読みます、そしてそれは非常に長くて私の記憶を爆破するかもしれません。

fgetsを使用すると、各呼び出し中に読み取るバイト数を指定し、基本的に1つの長い行を最大長に分割することができます。perlでこれを行う同様の方法はありますか?私は何かを見ましたsv_getsが、それをどのように使うのかわかりません(私は大雑把なグーグル検索をしただけですが)。

この演習の目的は、データの読み取り後に追加の解析/バッファリングを行う必要がないようにすることです。fgetsは、Nバイト後、または改行に達したときに停止します。

編集私はいくつか混乱したと思います。それぞれ最大長YのX行を読みたい。合計でZバイトを超えて読みたくないので、一度にすべてのZバイトを読みたくない。私はそれをして行を分割することができたと思いますが、他の方法があるかどうか疑問に思います。それが最善の方法である場合は、読み取り関数を使用して手動解析を実行するのが私の最も簡単な方法です。

ありがとう。

4

5 に答える 5

6

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;
}

$strPerlは日和見的に再割り当てするため、各文字をに連結すると効率的です。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」ではありませんが、誰が気にしますか?:) OS(そしておそらくPerl自体)は、その下で必要なすべてのバッファリングを行います。

于 2010-05-28T16:13:11.993 に答える
3

演習として、Cのfgets()関数のラッパーを実装しました。これは、「filenoのないもの」として定義された複雑なファイルハンドルの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を使用してこれらのリソース制限を設定します。優れたシステム管理者はとにかくリソース制限を設定しますが、プログラマーが妥当な制限を設定する起動スクリプトを作成するときにそれが好きです。

このデータを別のサイトにプロキシする前に入力を制限しようとしている場合(たとえば、リモートサイトが511文字を超えることをサポートしていない可能性があるため、SMTP入力行を制限する場合)、行の長さを.で確認して<INPUT>くださいlength()

于 2010-05-28T16:15:22.813 に答える