Я подготовил этот пример с помощью Mojo :: UserAgent . Для ввода CSV я использовал различные наборы данных из NY C Open Data . Это также появится в следующем обновлении для веб-клиентов Mojo .
. Я создаю запрос, не отправляя его сразу, и это дает мне объект транзакции $tx
. Затем я могу заменить событие read
, чтобы сразу отправить строки в Text :: CSV_XS :
#!perl
use v5.10;
use Mojo::UserAgent;
my $ua = Mojo::UserAgent->new;
my $url = ...;
my $tx = $ua->build_tx( GET => $url );
$tx->res->content->unsubscribe('read')->on(read => sub {
state $csv = do {
require Text::CSV_XS;
Text::CSV_XS->new;
};
state $buffer;
state $reader = do {
open my $r, '<:encoding(UTF-8)', \$buffer;
$r;
};
my ($content, $bytes) = @_;
$buffer .= $bytes;
while (my $row = $csv->getline($reader) ) {
say join ':', $row->@[2,4];
}
});
$tx = $ua->start($tx);
Это не так хорошо, как хотелось бы, потому что все данные все еще отображаются в буфере. Это немного более привлекательно, но это так, как я отмечаю в комментариях. Сейчас я слишком ленив, чтобы сделать это лучше, потому что это очень быстро становится волосатым, когда вы понимаете, что у вас достаточно данных для обработки записи. Мой конкретный код не так важен, как идея о том, что вы можете делать все, что угодно, так как транзакция читает данные и передает их в обработчик содержимого:
use v5.10;
use strict;
use warnings;
use feature qw(signatures);
no warnings qw(experimental::signatures);
use Mojo::UserAgent;
my $ua = Mojo::UserAgent->new;
my $url = ...;
my $tx = $ua->build_tx( GET => $url );
$tx->res->content
->unsubscribe('read')
->on( read => process_bytes_factory() );
$tx = $ua->start($tx);
sub process_bytes_factory {
return sub ( $content, $bytes ) {
state $csv = do {
require Text::CSV_XS;
Text::CSV_XS->new( { decode_utf8 => 1 } );
};
state $buffer = '';
state $line_no = 0;
$buffer .= $bytes;
# fragile if the entire content does not end in a
# newline (or whatever the line ending is)
my $last_line_incomplete = $buffer !~ /\n\z/;
# will not work if the format allows embedded newlines
my @lines = split /\n/, $buffer;
$buffer = pop @lines if $last_line_incomplete;
foreach my $line ( @lines ) {
my $status = $csv->parse($line);
my @row = $csv->fields;
say join ':', $line_no++, @row[2,4];
}
};
}