我正在从供应商那里得到一个“ csv文件”(使用他们的API),但是他们所做的只是将整个内容喷入他们的响应中。除了有一些讨厌的人输入数据并放入诸如换行符之类的“功能”之外,这不会是一个大问题。我现在正在做的是为原始数据创建一个文件,然后重新打开它以读取数据:
open RAW, ">", "$rawfile" or die "ERROR: Could not open $rawfile for write: $! \n";
print RAW $response->content;
close RAW;
my $csv = Text::CSV_XS->new({ binary=>1,always_quote=>1,eol=>$/ });
open my $fh, "<", "$rawfile" or die "ERROR: Could not open $rawfile for read: $! \n";
while ( $line = $csv->getline ($fh) ) { ...
以某种方式,这似乎……不雅。看来我应该能够从$ response-> content(多行字符串)中读取数据,就好像它是一个文件一样。但是我在如何做到这一点上完全空白。指针将不胜感激。谢谢,保罗
您可以使用字符串文件句柄:
my $data = $response->content;
open my $fh, "<", \$data or croak "unable to open string filehandle : $!";
my $csv = Text::CSV_XS->new({ binary=>1,always_quote=>1,eol=>$/ });
while ( $line = $csv->getline ($fh) ) { ... }
是,您可以通过其功能接口在字符串上使用Text::CSV_XS
use warnings;
use strict;
use feature 'say';
use Text::CSV_XS qw(csv); # must use _XS version
my $csv = qq(a,line\nand,another);
my $aoa = csv(in => \$csv)
or die Text::CSV->error_diag;
say "@$_" for @aoa;
请注意,这确实需要Text::CSV_XS
(通常Text::CSV有效,但与此无关)。
我不知道为什么这在OO界面中不可用(或者也许但没有记录)。
关于减轻“模糊”方面的注意,请注意,大多数库都允许您直接写入文件,例如:content_file
方法中的LWP::UserAgent::get选项。
让我也注意到,大多数时候您希望库对内容进行解码,因此LWP::UA
使用decoded_content
(请参阅HTTP::Response)。
我用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);
这不如我希望的那样好,因为所有数据仍显示在缓冲区中。这稍微更具吸引力,但是按照我在评论中指出的方式,它是脆弱的。我现在太懒了,无法改善它,因为当您确定何时有足够的数据来处理记录时,这会变得非常毛茸茸。我的特定代码并不重要,因为您可以做任何事情,就像事务处理程序读取数据并将其传递到内容处理程序中一样:
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];
}
};
}