Tôi đã đưa ra ví dụ này với Mojo :: UserAgent . Đối với đầu vào CSV, tôi đã sử dụng các bộ dữ liệu khác nhau từ Dữ liệu mở NYC . Điều này cũng sẽ xuất hiện trong bản cập nhật tiếp theo cho Mojo Web Client .
Tôi xây dựng yêu cầu mà không thực hiện yêu cầu ngay lập tức và điều đó mang lại cho tôi đối tượng giao dịch , $tx
. Sau đó tôi có thể thay thế read
sự kiện để tôi có thể gửi ngay các dòng vào 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);
Điều đó không tốt như tôi mong muốn vì tất cả dữ liệu vẫn hiển thị trong bộ đệm. Điều này hơi hấp dẫn hơn, nhưng nó dễ vỡ theo những cách tôi ghi chú trong các bình luận. Hiện tại tôi quá lười biếng để làm cho nó trở nên tốt hơn bởi vì nó sẽ nhanh chóng có lông khi bạn tìm ra khi bạn có đủ dữ liệu để xử lý một bản ghi. Mã cụ thể của tôi không quan trọng bằng ý tưởng rằng bạn có thể làm bất cứ điều gì bạn muốn khi giao dịch viên đọc dữ liệu và chuyển nó vào trình xử lý nội dung:
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];
}
};
}