我将有一个可能非常大的JSON文件,我想从它流,而不是将它全部加载到内存中。 基于JSON::XS的以下声明(我补充说明),我认为它不适合我的需求。 是否有一个Perl 5 JSON模块可以从磁盘中传输结果?

在某些情况下,需要对JSON文本进行增量解析。 虽然此模块始终必须同时将JSON文本和生成的Perl数据结构保留在内存中 ,但它确实允许您以递增方式解析JSON流。 它通过累积文本直到它具有完整的JSON对象来实现,然后它可以解码。 此过程类似于使用decode_prefix查看完整的JSON对象是否可用,但效率更高(并且可以使用最少的方法调用来实现)。

为了澄清,JSON将包含一个对象数组。 我想从文件中一次读取一个对象。

#1楼 票数:12

在易用性和速度方面, JSON::SL似乎是赢家:

#!/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"  }
]

JSON::Streaming::Reader是可以的,但速度较慢,并且接口过于冗长(尽管很多代码都不需要,但所有这些代码都是必需的):

#!/usr/bin/perl

use strict;
use warnings;

use JSON::Streaming::Reader;

my $p = JSON::Streaming::Reader->for_stream(\*DATA);

my $obj;
my $attr;
$p->process_tokens(
    start_array    => sub {}, #who cares?
    end_array      => sub {}, #who cares?
    end_property   => sub {}, #who cares?
    start_object   => sub { $obj = {}; },     #clear the current object
    start_property => sub { $attr = shift; }, #get the name of the attribute
    #add the value of the attribute to the object
    add_string     => sub { $obj->{$attr} = shift; },
    add_number     => sub { $obj->{$attr} = shift; },
    #object has finished parsing, it can be used now
    end_object     => sub { print "$obj->{n}: $obj->{s}\n"; },
);

__DATA__
[
    { "n": 0, "s": "zero" },
    { "n": 1, "s": "one"  },
    { "n": 2, "s": "two"  }
]

为了解析1,000条记录,它花了JSON::SL .2秒和JSON::Streaming::Reader 3.6秒(注意, JSON::SL一次被送入4k,我无法控制JSON :: Streaming :: Reader's缓冲区大小)。

#2楼 票数:3 已采纳

你有没有看过JSON :: Streaming :: Reader ,它在search.cpan.org上搜索'JSON Stream'时首先出现?

或者通过搜索“JSON SAX”找到JSON :: SL - 不是那么明显的搜索术语,但是你所描述的听起来像是用于XML的SAX解析器。

#3楼 票数:2

它通过累积文本直到它具有完整的JSON对象来实现,然后它可以解码。

这就是搞砸了你的东西。 JSON文档一个对象。

您需要从增量解析中更清楚地定义您想要的内容。 您在寻找大型映射的一个元素吗? 你想用你读出/写的信息做什么?


我不知道任何库会通过一次从数组中读出一个元素来逐步解析JSON数据。 然而,使用有限状态自动机实现这一点非常简单(基本上你的文件格式为\\s*\\[\\s*([^,]+,)*([^,]+)?\\s*\\]\\s*除了你需要正确解析字符串中的逗号。)

#4楼 票数:2

你有没有试过跳过右边的braket [然后是逗号,

$json->incr_text =~ s/^ \s* \[ //x;
...
$json->incr_text =~ s/^ \s* , //x;
...
$json->incr_text =~ s/^ \s* \] //x;

就像在第三个例子中一样: http//search.cpan.org/dist/JSON-XS/XS.pm#EXAMPLES

#5楼 票数:0

如果您可以控制如何生成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;
}

  ask by Chas. Owens translate from so

未解决问题?本站智能推荐:

1回复

从文件中流式传输数字

我希望有人可以帮我解决我在这里遇到的问题。 我的程序在下面,我遇到的问题是我无法弄清楚如何编写process()函数来获取带有一堆随机数的.txt文件,读取数字,并仅输出正数到一个单独的文件。 我已经被困在这几天了,我不知道还能在哪里转。 如果有人能提供任何形式的帮助,我将非常感激,谢谢。
2回复

将JSON可解析的数组流式传输到文件

因此,您正在从文件读取数据,清除数据,然后将其写回到另一个文件,但是新文件不接受JSON格式。 您需要在新文件中填充一个对象。 您可以从文件中获取一个块,对其进行更改,然后将其保存到新文件中。 为此,您将数据流传输出去,编辑块,然后将其流回到另一个文件中。 大。 您一定要
1回复

在Node.js中流式传输响应数据时缺少块

从axios获得响应后,我将其转换为流。获得一些块stream.on("end"正在执行。由于这个原因,我得到了 对于正常数据(来自API的响应),它可以正常工作。 但是,对于巨大的响应,缺少了很多块。 我也试图将大块保存在数组中,但是没有用。 对于与Postman尝试使用的相
2回复

将Curl的JSON结果流式传输到Curl的数据参数中

我正在尝试将JSON输出从一个curl传输到另一个curl的data参数中。 可能? 步骤1:例如,输出JSON的curl是: 返回: 第2步:如果在第二个curl中使用第一个curl的输出,那么我将获得成功的响应: 成功回应: 步骤1和步骤2合并:我正在
1回复

在Perl中,如何将URL列表从文件流式传输到数组中,然后以递归方式在单个文件中获取其所有HTML数据?

另一个麻烦的标题...对不起...总之,我有一个名为mash.txt的文件, mash.txt包含许多这样的URL: http://www... http://www... http://www... . . . 因此,在这一点上,我想将这些(URL)馈
2回复

捕获输出以流式传输并存储为字符串变量

尽管这个问题与“ BioPerl”有关,但我认为这个问题可能比这更笼统。 基本上,我产生了一个Bio :: Tree :: TreeI对象,并且我试图将其转换为字符串变量。 我接近将其转换为字符串变量的唯一方法是使用以下命令将该树写入流中: -> write_tree的
2回复

使用QTimer在Python中流式传输大型数据文件

我首先要说的是我有有效的代码...但这并不能使它成为理想的代码,这就是为什么我要由社区来使用我的方法。 我正在尝试以“ QT方式”执行此操作,这迫使我沿着通常不去的路走。 我有一些包含原始时变数据的400 + mb二进制文件。 我需要将此数据绘制给用户,以便数据回放与记录的持续时间匹配
1回复

在Node.js中流式传输大文件

我有一种情况,我需要同时传输例如100个文件,但是我不知道天气是否需要子进程,因为我不确定是否有一个非常大的文件会阻止其他文件传输。 任何人都可以帮助澄清在这种情况下应采取的措施。 我是否需要产生一个子流程? 还是我可以在一个过程中同时流式传输所有内容?