【问题标题】:splitting a big json file and setting the name of the output file拆分一个大的 json 文件并设置输出文件的名称
【发布时间】:2016-04-23 00:19:11
【问题描述】:

我有一个大的 JSON 对象文件(超过 12000 行),看起来像:

{
     "System": "2334", 
     "Id": "AP64531346-2016055553824", 
     "dtis": "106165099", 
     "Type": "Up",
     ... (in total, 112 lines per record)
}
{
     "System": "873", 
     "Id": "AP24531346-20160676553824", 
     "dtis": "1261699", 
     "Type": "Up",
     ... (in total, 112 lines per record)
}

我想将大文件拆分成小文件,每个文件都有一个入口(112 行),并将每个文件的名称设置为“Id”的值,例如 AP64531346-2016055553824.txt 和 AP24531346-分别为20160676553824。

我尝试使用 GNU Split,但我无法将每个文件的名称设置为 Id 加 .txt。

split -l 112 ../bigfile.csv 

有什么建议吗?

【问题讨论】:

    标签: python json perl shell awk


    【解决方案1】:

    分两步:首先生成通用命名的文件

    split -l 112 ../bigfile.csv
    

    现在您有了名为xaaxab 等的文件。我假设这些是目录中唯一的文件。现在您可以遍历它们,提取 Id 并重命名它们:

    for file in *; do
        newname="$(grep -m 1 -Po '(?<="Id": ")[^"]+' "$file")"
        mv "$file" "$newname.txt"
    done
    

    grep -o 仅提取匹配项,并使用零宽度“look-behind”来获取 Id 行。环视仅在使用 Perl 正则表达式引擎 (-P) 时可用。 -m 1 在第一场比赛后停止,因此当您知道第一场比赛已经足够好时,您不会浏览整个文件。

    当每个块没有 112 行时,这当然会很糟糕——proper solution 会解析文件。

    【讨论】:

      【解决方案2】:

      听起来您想将每个 JSON 文档放在自己的文件中。您可以使用 JSON::XS 的增量解析器来执行此操作。

      use JSON::XS qw( );
      
      my $json = JSON::XS->utf8->new();
      
      local $/ = \(1024*1024)
      while (<>) {
         for my $obj ($json->incr_parse($_)) {
            my $id = $obj->{Id};
            open(my $fh, '>', $id . ".txt")
               or die $!;
            print($fh $json->encode($obj));
         }
      }
      

      【讨论】:

      • 请注意,这将导致数据中的键以与原始不同的顺序出现。如果数据确实和描述的一样,最好$/ = "\n}\n"; while (my $record = &lt;&gt;) { my $id = $json-&gt;decode($record)-&gt;{Id}; open(my $fh,...) or die; print $fh $record }(仅带错误检查)
      • @ysth,正确,但键顺序在 JSON 中没有意义。至于评论的其余部分,您为什么不将其发布为答案?
      • 看起来和你的差别太小了
      • @ysth,就我而言,完全不同的方法,但无论如何
      • @ysth:我更喜欢你的解决方案并同意你应该发布它
      【解决方案3】:

      任务的一般方法(即,不对输入文件中的 JSON 实体流做出任何假设,除了它们是有效的 JSON 实体的方法)由以下“单线”说明:

      jq -cr '"\(.Id)\t\(.)"' | awk -F\\t '{print $2 > "/tmp/"$1".json"}'
      

      这使用“JSON 查询”(jq) 命令行处理器,该处理器可在许多平台上使用。

      如果您希望每个新文件都打印得很漂亮,那么您也可以在第二步中使用 jq 来实现,例如:

      ls *.json | while read f ; do jq . "$f" > "$f.tmp" && mv "$f.tmp" "$f" ; done
      

      【讨论】:

      • 您知道 OP 发布的不是有效的 JSON,而是将组合在一个文件中的有效 JSON 的 sn-ps 相乘?
      • 您知道我在您发表评论前 11 小时左右相应地编辑了帖子吗?
      【解决方案4】:

      JSON 结构与 perl 数据结构高度兼容,因此可以使用 eval 快速分离不同文件中的记录。考虑到您的 json 值中没有“:”

      local $/ = undef;
      open FILE, "Testjson.txt" or die "Couldn't open file: $!";
      my $string = <BiGFILE>;
      close FILE;
      $string =~ s/:/,/g;  
      $jsonStr = eval $string;
      
      foreach my $record (@{$jsonStr}) {
       print $record->{'Id'} . "\n";
      }
      

      【讨论】:

        猜你喜欢
        • 2017-08-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-01
        • 1970-01-01
        • 2021-12-31
        相关资源
        最近更新 更多