разделить плоский файл размером 60 ГБ с записями, иногда охватывающими несколько строк

разделить плоский файл размером 60 ГБ с записями, иногда охватывающими несколько строк

Ручной ввод данных загрязняет базу данных записями, содержащими несколько символов новой строки. Для хороших записей, разделенных двойными кавычками в начале и в конце в огромном плоском файле размером 60 ГБ с одним столбцом, они всегда должны охватывать только одну строку, как здесь:

«Теперь доступны полные последовательности многочисленных митохондриальных, многих прокариотических и нескольких ядерных геномов».

Для плохих записей они охватывают неопределенное количество строк, например:

«Текущее курение было тесно и обратно связано с высоким риском

Модели, после корректировки на сопутствующие факторы риска. Относительно никогда

курильщики, нынешние курильщики значительно реже имели высокий риск

шаблон. "

Эти многострочные записи запрещают последующее разделение файла командой UNIX split. splitне может разумно распознать эти несколько строк как одну запись, и это может привести к разделению одной записи на отдельные файлы. Perl ниже слишком медленный, чтобы сначала объединить эти строки для плохих записей для этого огромного файла перед разделением, поскольку $count не может быть напечатан после ожидания более 2 часов.

$file=$ARGV[0];
open(INFO, $file) or die("Could not open $file.");
open(OUT, ">out") or die("Could not open $file.");

$mergedline = "";
$count=0;
foreach $line (<INFO>)  {
    print $count++;
    if ($line =~ /^".*"\n$/) {
                print OUT $line;
                $mergedline = "";
                next;
        } elsif ($line =~ /"\n$/) {
                print OUT $mergedline;
                $mergedline = "";
                next;
        } else {
                chomp $line;
                $mergedline .= $line;
        }
}
close(INFO);

Есть ли удобная команда UNIX для решения этой проблемы, чтобы выходной файл был «чистым» и содержал только однострочные записи, которые можно обработать split?

sedкажется, это вариант, но ни один из следующих постов не отвечает на этот вопрос:

https://stackoverflow.com/questions/15758814/превращение-нескольких-строк-в-одну-строку-с-разделителями-запятыми-perl-sed-awk

https://stackoverflow.com/questions/11290616/sed-conditional-merge-of-multiple-lines

http://www.unix.com/shell-programming-and-scripting/80633-sed-combining-multiple-lines-into-one.html

потому что шаблоны этих постов слишком регулярны и постоянны.

решение1

Используется sedтолько для соединения разделенных линий.

sed ':a
/".*"$/b
N;s/\n/ /;ba' input >> output

На моей системе файл размером 10 МБ загружается за 6 секунд. Для 60 ГБ это займет 10 часов.

bbeнемного быстрее

bbe -b '/"/:/"/' -o output -e 'y/\n/ /' input

но все равно занимает 4 секунды.

Боюсь, эти скриптовые языки не подходят для работы с очень большими файлами. А как насчет написания небольшой программы на C?

решение2

пример использования gawk:

awk 'BEGIN {RS = "\"\n"} {++n; print $0"\""> n".txt"}' input

Это говорит о разделении файла inputна любую последовательность, за которой "следует символ новой строки ( \n). Это проигнорирует символы новой строки, которые не следуют сразу за кавычками, сохраняя многострочные записи. В этом примере вывод записывается в текстовый файл, но если вы удалите эту > n".txt"часть, вы можете вместо этого отправить записи в конвейер.

решение3

Ваш Perlмедленный из-за forцикла, используемого для чтения файла. Вам действительно следует использовать цикл while, поскольку forцикл загружает весь файл в память за один раз. Вот почему печать $count занимает вечность.

perl -ne '
   print,next if /^".*"$/m or /"$/m;
   chomp, $_ .= <>, redo unless eof;
' gene.data

Связанный контент