He preparado este ejemplo con Mojo :: UserAgent . Para la entrada CSV utilicé varios conjuntos de datos de NYC Open Data . Esto también aparecerá en la próxima actualización para Mojo Web Clients .
Construyo la solicitud sin realizar la consulta de inmediato, y eso me da el objeto de transacción, $tx
. Entonces puedo reemplazar el read
evento para poder enviar inmediatamente las líneas a 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);
Eso no es tan bueno como me gustaría que sea porque todos los datos aún se muestran en el búfer. Esto es un poco más atractivo, pero es frágil en las formas que noto en los comentarios. Soy demasiado vago en este momento para mejorarlo porque eso se vuelve muy rápido cuando te das cuenta de que tienes suficientes datos para procesar un registro. Mi código particular no es tan importante como la idea de que puedes hacer lo que quieras mientras el transactor lee los datos y los pasa al controlador de contenido:
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];
}
};
}