如何从文件中传输JSON?
我将有一个可能非常大的JSON文件,我希望从中流式传输,而不是将其全部加载到内存中。根据以下声明(我添加了重点),我认为它不适合我的需要。是否有一个Perl5JSON模块将从磁盘流式传输结果 在某些情况下,需要对JSON文本进行增量解析。虽然此模块总是必须同时将JSON文本和生成的Perl数据结构保存在内存中,但它确实允许您增量解析JSON流。它通过累积文本直到拥有一个完整的JSON对象,然后对其进行解码来实现这一点。这个过程类似于使用decode_前缀来查看是否有完整的JSON对象可用,但效率要高得多(并且可以通过最少的方法调用来实现) 为了澄清这一点,JSON将包含一个对象数组。我想从文件中一次读取一个对象 它通过累积文本直到拥有一个完整的JSON对象,然后对其进行解码来实现这一点 这就是你被搞砸的地方。JSON文档是一个对象 您需要更清楚地定义您想要从增量解析中得到什么。您正在寻找大型映射的一个元素吗?你想对你读/写的信息做什么如何从文件中传输JSON?,json,perl,stream,Json,Perl,Stream,我将有一个可能非常大的JSON文件,我希望从中流式传输,而不是将其全部加载到内存中。根据以下声明(我添加了重点),我认为它不适合我的需要。是否有一个Perl5JSON模块将从磁盘流式传输结果 在某些情况下,需要对JSON文本进行增量解析。虽然此模块总是必须同时将JSON文本和生成的Perl数据结构保存在内存中,但它确实允许您增量解析JSON流。它通过累积文本直到拥有一个完整的JSON对象,然后对其进行解码来实现这一点。这个过程类似于使用decode_前缀来查看是否有完整的JSON对象可用,但效率
我不知道有哪个库会通过一次从数组中读取一个元素来增量解析JSON数据。但是,使用有限状态自动机实现这一点非常简单(基本上,您的文件的格式是
\s*\[\s*([^,]+,)*([^,]+)?\s*\]\s*
,除非您需要正确解析字符串中的逗号。)您是否尝试先跳过右括号[
,然后跳过逗号,
:
$json->incr_text =~ s/^ \s* \[ //x;
...
$json->incr_text =~ s/^ \s* , //x;
...
$json->incr_text =~ s/^ \s* \] //x;
就像第三个例子:
在search.cpan.org上搜索“JSON流”时,您是否查看了第一个显示的内容
或者通过搜索“JSON SAX”来找到—虽然不是很明显的搜索词,但您描述的内容听起来像是XML的SAX解析器。就易用性和速度而言,似乎是赢家:
#!/usr/bin/perl
use strict;
use warnings;
use JSON::SL;
my $p = JSON::SL->new;
#look for everthing past the first level (i.e. everything in the array)
$p->set_jsonpointer(["/^"]);
local $/ = \5; #read only 5 bytes at a time
while (my $buf = <DATA>) {
$p->feed($buf); #parse what you can
#fetch anything that completed the parse and matches the JSON Pointer
while (my $obj = $p->fetch) {
print "$obj->{Value}{n}: $obj->{Value}{s}\n";
}
}
__DATA__
[
{ "n": 0, "s": "zero" },
{ "n": 1, "s": "one" },
{ "n": 2, "s": "two" }
]
解析1000条记录花了
JSON::SL
0.2秒和JSON::Streaming::Reader
3.6秒(注意,JSON::SL
一次输入4k,我无法控制JSON::Streaming::Reader的缓冲区大小).如果您可以控制如何生成JSON,那么我建议您关闭格式设置,每行打印一个对象。这使得解析变得简单,如下所示:
use Data::Dumper;
use JSON::Parse 'json_to_perl';
use JSON;
use JSON::SL;
my $json_sl = JSON::SL->new();
use JSON::XS;
my $json_xs = JSON::XS->new();
$json_xs = $json_xs->pretty(0);
#$json_xs = $json_xs->utf8(1);
#$json_xs = $json_xs->ascii(0);
#$json_xs = $json_xs->allow_unknown(1);
my ($file) = @ARGV;
unless( defined $file && -f $file )
{
print STDERR "usage: $0 FILE\n";
exit 1;
}
my @cmd = ( qw( CMD ARGS ), $file );
open my $JSON, '-|', @cmd or die "Failed to exec @cmd: $!";
# local $/ = \4096; #read 4k at a time
while( my $line = <$JSON> )
{
if( my $obj = json($line) )
{
print Dumper($obj);
}
else
{
die "error: failed to parse line - $line";
}
exit if( $. == 5 );
}
exit 0;
sub json
{
my ($data) = @_;
return decode_json($data);
}
sub json_parse
{
my ($data) = @_;
return json_to_perl($data);
}
sub json_xs
{
my ($data) = @_;
return $json_xs->decode($data);
}
sub json_xs_incremental
{
my ($data) = @_;
my $result = [];
$json_xs->incr_parse($data); # void context, so no parsing
push( @$result, $_ ) for( $json_xs->incr_parse );
return $result;
}
sub json_sl_incremental
{
my ($data) = @_;
my $result = [];
$json_sl->feed($data);
push( @$result, $_ ) for( $json_sl->fetch );
# ? error: JSON::SL - Got error CANT_INSERT at position 552 at json_to_perl.pl line 82, <$JSON> line 2.
return $result;
}
使用数据::转储程序;
使用JSON::解析“JSON_to_perl”;
使用JSON;
使用JSON::SL;
我的$json_sl=json::sl->new();
使用JSON::XS;
我的$json_xs=json::xs->new();
$json_xs=$json_xs->pretty(0);
#$json_xs=$json_xs->utf8(1);
#$json_xs=$json_xs->ascii(0);
#$json_xs=$json_xs->allow_unknown(1);
我的($file)=@ARGV;
除非(定义为$file&&f$file)
{
打印STDERR“用法:$0文件\n”;
出口1;
}
my@cmd=(qw(cmd参数),$file);
打开我的$JSON、'-|'、@cmd或die“无法执行@cmd:$!”;
#本地$/=\4096;#一次读取4k
while(我的$line=)
{
if(my$obj=json($line))
{
打印转储程序($obj);
}
其他的
{
die“错误:无法分析行-$line”;
}
如果($==5)退出;
}
出口0;
子json
{
我的($数据)=@;
返回decode_json($data);
}
子json_解析
{
我的($数据)=@;
将json_返回到_perl($data);
}
子json_xs
{
我的($数据)=@;
返回$json_xs->decode($data);
}
子json_xs_增量
{
我的($数据)=@;
我的$result=[];
$json_xs->incr_parse($data);#无效上下文,因此没有解析
推送(@$result,$)($json_xs->incr_parse);
返回$result;
}
子json_sl_增量
{
我的($数据)=@;
我的$result=[];
$json_sl->feed($data);
为($json_sl->fetch)推送(@$result,$);
#?错误:JSON::SL-在JSON_至_perl.pl第82行第2行的位置552处出现错误无法插入。
返回$result;
}
我更新了这个问题,JSON是一个对象数组,我一次只想要一个对象。我想你……你是在找人来证明某个模块吗?我的初步搜索显示,JSON是一个潜在的候选对象,但不知道它们是否适合你的需要。@Zaid我只是在看JSON模块,我不认为需要lude stream的名字(我错误地认为顶级狗会有这个功能)。我还没有尝试过任何东西,文档似乎说它仍然在内存中保存东西(即没有像XML::Twig
has那样的刷新).事实上,第四个例子似乎做了你想做的事情。看起来是这样,但它看起来像地狱一样粗糙。显然CPAN上还有其他专门的模块可以对我隐藏这些粗糙之处。我现在正在查看它们。我现在正在将文档读到JSON::SL,接下来我将查看JSON::Streaming::Reader。作为JSON::SL的作者,它提供了rs既有一个拉式接口(如下面的示例所示),也有一个实际的SAX式接口(称为Tuba
)。它们是不同的,SAX式接口的缺点是显而易见的(复杂且缓慢)
use Data::Dumper;
use JSON::Parse 'json_to_perl';
use JSON;
use JSON::SL;
my $json_sl = JSON::SL->new();
use JSON::XS;
my $json_xs = JSON::XS->new();
$json_xs = $json_xs->pretty(0);
#$json_xs = $json_xs->utf8(1);
#$json_xs = $json_xs->ascii(0);
#$json_xs = $json_xs->allow_unknown(1);
my ($file) = @ARGV;
unless( defined $file && -f $file )
{
print STDERR "usage: $0 FILE\n";
exit 1;
}
my @cmd = ( qw( CMD ARGS ), $file );
open my $JSON, '-|', @cmd or die "Failed to exec @cmd: $!";
# local $/ = \4096; #read 4k at a time
while( my $line = <$JSON> )
{
if( my $obj = json($line) )
{
print Dumper($obj);
}
else
{
die "error: failed to parse line - $line";
}
exit if( $. == 5 );
}
exit 0;
sub json
{
my ($data) = @_;
return decode_json($data);
}
sub json_parse
{
my ($data) = @_;
return json_to_perl($data);
}
sub json_xs
{
my ($data) = @_;
return $json_xs->decode($data);
}
sub json_xs_incremental
{
my ($data) = @_;
my $result = [];
$json_xs->incr_parse($data); # void context, so no parsing
push( @$result, $_ ) for( $json_xs->incr_parse );
return $result;
}
sub json_sl_incremental
{
my ($data) = @_;
my $result = [];
$json_sl->feed($data);
push( @$result, $_ ) for( $json_sl->fetch );
# ? error: JSON::SL - Got error CANT_INSERT at position 552 at json_to_perl.pl line 82, <$JSON> line 2.
return $result;
}