В Perl я могу ограничить длину строки, когда я считал его в из файла (как fgets)?

Я пытаюсь записать часть кода, который читает файл линию за линией и хранит каждую строку до определенного количества входных данных. Я хочу принять меры против конечного пользователя, являющегося злым и помещающего что-то как концерт данных по одной строке в дополнение к принятию мер против впитывания неправильно большого файла. Выполнение $str = <FILE> будет все еще читать в целой строке, и это могло быть очень длинно и аварийно завершить мою память.

fgets позволяет мне сделать это, позволяя мне указать многие байты для чтения во время каждого вызова и по существу разрешения мне разделить одну длинную линию на мою макс. длину. Существует ли похожий способ сделать это в жемчуге? Я видел что-то о sv_gets но не уверено, как использовать его (хотя я только сделал поверхностный поиск Google).

Цель этого осуществления состоит в том, чтобы избежать необходимости делать дополнительный парсинг / буферизующий после чтения данных. остановки fgets после N байты или когда новая строка достигнута.

РЕДАКТИРОВАНИЕ я думаю, что смутил некоторых. Я хочу считать X строк, каждого с макс. длиной Y. Я не хочу читать больше, чем общее количество байтов Z, и я предпочел бы не читать все байты Z сразу. Я предполагаю, что мог просто сделать это и разделить строки, но задающийся вопросом, существует ли некоторый другой путь. Если это - лучший способ, то использование функции чтения и выполнение ручного синтаксического анализа являются моей самой легкой ставкой.

Спасибо.

8
задан brian d foy 28 May 2010 в 17:49
поделиться

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.

5
ответ дан 5 December 2019 в 15:20
поделиться

В качестве упражнения я реализовал оболочку для функции C fgets (). Он возвращается к реализации Perl для сложных дескрипторов файлов, определенных как «что-нибудь без файла», чтобы покрыть связанные дескрипторы и тому подобное. File :: fgets сейчас находится на пути к CPAN, вы можете получить копию из репозитория.

Некоторые базовые тесты показывают, что он более чем в 10 раз быстрее, чем любая из приведенных здесь реализаций. Тем не менее, я не могу сказать, что в нем нет ошибок или утечки памяти, мои навыки XS не так хороши, но его лучше протестировать, чем что-либо здесь.

3
ответ дан 5 December 2019 в 15:20
поделиться

Используйте функцию чтения (чтение perlfunc)

1
ответ дан 5 December 2019 в 15:20
поделиться

Вы можете легко реализовать 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 символов), то просто проверьте длину строки после с длиной () .

-2
ответ дан 5 December 2019 в 15:20
поделиться
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) сделает всю необходимую буферизацию под себя.

4
ответ дан 5 December 2019 в 15:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: