我用Mojo::UserAgent 编写了这个示例。对于 CSV 输入,我使用了来自 NYC Open Data 的各种数据集。这也将出现在Mojo Web Clients 的下一次更新中。
我在没有立即发出请求的情况下构建请求,这给了我事务对象$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);
这并不像我希望的那样好,因为所有数据仍显示在缓冲区中。这有点吸引人,但在我在 cmets 中注意到的方式中它很脆弱。我现在懒得让它变得更好,因为当你知道什么时候有足够的数据来处理记录时,它会很快变得毛茸茸。我的特定代码并不像您可以随心所欲地做任何事情的想法那么重要,因为交易者会读取数据并将其传递给内容处理程序:
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];
}
};
}