Я хотел бы иметь функцию печати, поддерживающую настраиваемый пользователем буфер, [...]
Я представляю что-то вроде этого: [...]
Не сложно написать что-то подобное. Вот базовый c набросок
Файл PrintBuffer.pm
package PrintBuffer;
use warnings;
use strict;
sub new {
my ($class, %args) = @_;
my $self = {
_size => $args{size} // 64*1024, #//
_fh => $args{filehandle} // *STDOUT,
_buf => ''
};
$self->{_fh}->autoflush; # want it out once it's printed
bless $self, $class;
}
sub print {
my ($self, $string) = @_;
$self->{_buf} .= $string;
if ( length($self->{_buf}) > $self->{_size} ) {
print { $self->{_fh} } $self->{_buf};
$self->{_buf} = '';
}
return $self;
}
sub DESTROY {
my $self = shift;
print { $self->{_fh} } $self->{_buf} if $self->{_buf} ne '';
$self->{_buf} = '';
}
1;
Здесь есть еще кое-что, что можно добавить, и поскольку оно опирается только на c инструменты, которые можно добавлять / изменять по своему усмотрению. † Для одного я могу представить size
метод для управления размером буфера существующего объекта (выведите, если данных уже больше, чем новый размер) ) и flush
.
Обратите внимание, что метод DESTROY
предусматривает печать буфера, когда объект выпадает из любой области видимости и уничтожается, что представляется разумным.
Драйвер
use warnings;
use strict;
use feature 'say';
use PrintBuffer;
my $fout = shift // die "Usage: $0 out-file\n";
open my $fh, '>', $fout or die "Can't open $fout: $!";
my $obj_file = PrintBuffer->new(size => 100, filehandle => $fh);
my $obj_stdout = PrintBuffer->new(size => 100);
$obj_file->print('a little bit');
$obj_stdout->print('a little bit');
say "printed 'a little bit' ..."; sleep 10;
$obj_file->print('out'x30); # push it over a 100 chars
$obj_stdout->print('out'x30);
say "printed 'out'x30 ... "; sleep 10;
$obj_file->print('again...'); # check DESTROY
$obj_stdout->print('again');
say "printed 'again' (and we're done)";
Проверяйте размер выходного файла в другом терминале после каждого информационного отпечатка.
Я попробовал PerlIO :: buffersize , который поднял Гриннц в комментарии, и кажется, что он работает "как рекламируется", как они говорят. Он не позволяет вам делать все возможное с sh, но может быть готовым решением для базовых c нужд. Обратите внимание, что это не работает с используемым слоем :encoding
.
Спасибо ikegami за комментарии и тесты (ссылки в комментариях).
† print
работает с ручкой autoflush
. Тем не менее, первое изменение может заключаться в использовании вместо этого syswrite , который небуферизован и пытается напрямую написать все, что от него требуется, с помощью одного write(2)
вызова. Но поскольку нет гарантии, что все написано, нам также нужно проверить
use Carp; # for croak
WRITE: {
my $bytes_written = 0;
while ( $bytes_written < length $self->{_buf} ) {
my $rv = syswrite(
$self->{_fh},
$self->{_buf},
length($self->{_buf}) - $bytes_written,
$bytes_written
);
croak "Error writing: $!" if not defined $rv;
$bytes_written += $rv;
}
$self->{_buf} = '';
};
Я поместил это в блок только для ограничения области действия $bytes_written
и любых других переменных, которые могут быть wi sh ввести так, чтобы уменьшить количество разыменований $self
(но учтите, что $self->{_buf}
может быть довольно большим, и копирование его "для оптимизации" разыменования может закончиться медленнее).
Наивно мы бы только нужно syswrite(FH, SCALAR)
, но если случится так, что не все из SCALAR
будут записаны, тогда нам нужно продолжать писать из прошлого того, что было написано, таким образом, необходимо использовать форму с длиной записи и смещением.
Поскольку это небуферизованное, его нельзя смешивать с буферизованным вводом-выводом (или это нужно делать очень осторожно); смотри документы. Кроме того, :encoding
слои не могут быть использованы с ним. Учитывайте эти ограничения в отношении других возможностей, которые могут потребоваться в этом классе.