2016-01-17 5 views
0

У меня есть большой файл в формате JSON объектов (более 12000 строк), который выглядит как:расщепление большого файла JSON и установив имя выходного файла

{ 
    "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, но я не могу установить имя каждого файла как идентификатор плюс .txt.

split -l 112 ../bigfile.csv 

Любое предложение?

ответ

2

В два этапа: сначала сгенерировать обобщенно названные файлы с

split -l 112 ../bigfile.csv 

Теперь у вас есть файлы с именем xaa, xab и т.д. Я предполагаю, что это единственные файлы в каталоге. Теперь вы можете петлю над ними, извлечь Id и переименовать их:

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

grep -o выписки только матч, и использует нулевую ширину «Двойник за», чтобы получить линию Id. Обзоры доступны только при использовании движка regex Perl (-P). -m 1 останавливается после первого матча, поэтому вы не просматриваете весь файл, если знаете, что первый матч достаточно хорош.

Это, конечно, сильно не работает, если не существует 112 строк на блок. – a 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)); 
    } 
} 
+2

Обратите внимание, что это приведет к тому, что ключи данных будут выдаваться в другом порядке, чем оригинал. Если данные на самом деле описаны так, это может быть лучше '$/=" \ n} \ n "; while (my $ record = <>) {my $ id = $ json-> decode ($ record) -> {Id}; открыть (my $ fh, ...) или умереть; print $ fh $ record} '(только при проверке ошибок) – ysth

+0

@ysth, Правильно, но порядок клавиш в JSON не имеет смысла. Что касается остальной части комментария, почему бы вам не опубликовать его как ответ? – ikegami

+0

казался слишком мало отличающимся от вашего – ysth

1

Общий подход к задаче (то есть, подход, который не делает никаких предположений о потоке 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 
+0

Вы знаете, что то, что опубликовано OP недействительно JSON, но rater умножает фрагменты действительного JSON, объединенные в один файл? – andlrc

+0

Вы знаете, что я отредактировал сообщение, соответственно, за 11 часов до вашего комментария? – peak

1

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"; 
} 
Смежные вопросы