2012-03-30 6 views
8

У меня есть файлы CSV, которые отсортированы по нескольким столбцам. Например, я мог бы иметь такие строки:Разделить большой текстовый файл csv на основе значения столбца

19980102,,PLXS,10032,Q,A,,,15.12500,15.00000,15.12500,2 
19980105,,PLXS,10032,Q,A,,,14.93750,14.75000,14.93750,2 
19980106,,PLXS,10032,Q,A,,,14.56250,14.56250,14.87500,2 
20111222,,PCP,63830,N,A,,,164.07001,164.09000,164.12000,1 
20111223,,PCP,63830,N,A,,,164.53000,164.53000,164.55000,1 
20111227,,PCP,63830,N,A,,,165.69000,165.61000,165.64000,1 

Я хотел бы разделить файл на основе 3-го столбца, например, помещать записи PLXS и PCP в свои собственные файлы, называемые PLXS.csv и PCP.csv. Поскольку файл предварительно отсортирован, все записи PLXS находятся перед входами PCP и так далее.

Я вообще делаю такие вещи, как это на C++, так как это язык, который я знаю лучше всего, но в этом случае мой входной файл CSV составляет несколько гигабайт и слишком большой для загрузки в память на C++.

Может ли кто-нибудь показать, как это можно сделать? Решения Perl/Python/php/bash все в порядке, они просто должны иметь возможность обрабатывать огромный файл без чрезмерного использования памяти.

+0

ты просмотрел вокруг на всех? несколько связанных вопросов на этом сайте на всех вышеперечисленных языках и многое другое. вы можете искать: 'site: stackoverflow.com csv split by value' или какой-то такой вариант. удачи – bernie

ответ

1

C++ прекрасно, если вы знаете это лучше всего. Почему вы все равно пытаетесь загрузить весь файл в память?

Поскольку выходной сигнал зависит от прочитанного столбца, вы можете легко хранить буферы для выходных файлов и записывать запись в соответствующий файл по мере процесса обработки, очищая по мере того, как вы уходите, чтобы сохранить размер памяти относительно небольшим.

Я делаю это (хотя и в java), когда нужно брать массивные выдержки из базы данных. Записи вставляются в поток файлового буфера, и все в памяти очищается, поэтому след программы никогда не растет выше того, из чего она начинается.

Fly седло моих штанов псевдо-код:

  1. Создание списка для хранения ваших выходных буферов файлов
  2. Открыть потока в файл и начать читать в содержании одной линии в то время
  3. Неужели мы столкнулись с записью, которая имеет открытый поток файлов для своего типа контента?
    • Да -
      • Получить сохраненный поток файла
      • магазин запись в этот файл
      • Промывайте поток
    • Нет -
      • не создать поток и сохранить его наш список потоков
      • хранить запись на потоке
      • вровень поток
  4. Промывка повтор ...

В основном продолжает эту обработку, пока мы в конце файла.

Поскольку мы никогда не храним больше указателей на потоки, и мы смываем, как только мы пишем в потоки, мы никогда не держим ничего в памяти приложения, отличного от одной записи из входного файла. Таким образом, след остается регулируемым.

+2

+1: C++ не проблема. Проблема с загрузкой всего файла в память. –

0

Альтернативным решением было бы загрузить CSV в индекс Solr, а затем сгенерировать CSV-файлы на основе ваших пользовательских критериев поиска.

Вот основной HOWTO:

Create report and upload to server for download

26

Вот старая школа один лайнер для вас (просто заменить >> с > укоротить выходных файлов каждого запуска):

awk -F, '{print >> ($3".csv")}' input.csv 

Due к популярному спросу (и к зуду, который у меня только что был), я также написал версию, которая будет дублировать строки заголовков ко всем файлам:

awk -F, '{fn=$3".csv"} NR==1 {hdr=$0} NR>1&&!($3 in p) {p[$3]; print hdr > fn} NR>1 {print >> fn}' input.csv 

Но вы могли бы просто начать с этого и закончить с первой AWK:

HDR=$(head -1 input.csv); for fn in $(tail -n+2 input.csv | cut -f3 -d, | sort -u); do echo $HDR > $fn.csv; done 

Большинством современных систем есть AWK двоичная включены, но если вы не имеете его, вы можете найти ех на Gawk for Windows

+0

это потрясающе :) было бы еще лучше, если бы мы могли сохранить заголовки –

+1

В оригинале не было заголовков. Возможно, вы можете задать другой вопрос? –

0

Если первые три столбца файла не котируемые запятые, простой один-лайнер:

cat file | perl -e 'while(<>){@a=split(/,/,$_,4);$key=$a[2];open($f{$key},">$key.csv") unless $f{$key};print {$f{$key}} $_;} for $key (keys %f) {close $f{$key}}' 

Он не потребляет много памяти (только Asso ciations различаются (3rd_column) -> file-handle), и строки могут поступать в любом порядке.

Если столбцы более сложные (например, содержат запятые), используйте Text::CSV. используются

+0

На самом деле, я просто замечаю, что это по сути тот же ответ, что и у Шона Саммерса ниже. –

1
perl -F, -ane '`echo $_ >> $F[2].csv`' < file 

Эти параметры командной строки:

  • -n петлю вокруг каждой строки входного файла
  • -l удаляет символы новой строки перед обработкой, и добавляет их обратно впоследствии
  • -a AutoSplit mode - разделение входных строк на массив @F. По умолчанию разбивается на пробелы.
  • -e выполнить код PERL
  • -F модификатор Autosplit, в этом случае расщепляется на ,

@F это массив слов в каждой строке, индексной начиная с $F[0]


Если вы хотите сохранить заголовок, то требуется более сложный подход.

perl splitintofiles.pl file

Содержание splitintofiles.пл:

open $fh, '<', $ARGV[0]; 
while ($line = <$fh>) { 
    print $line; 
    if ($. == 1) { 
     $header = $line; 
    } else { 
     # $fields[2] is the 3rd column 
     @fields = split /,/, $line; 
     # save line into hash %c 
     $c{"$fields[2].csv"} .= $line; 
    } 
} 
close $fh; 
for $file (keys %c) { 
    print "$file\n"; 
    open $fh, '>', $file; 
    print $fh $header; 
    print $fh $c{$file}; 
    close $fh; 
} 

вход:

a,b,c,d,e,f,g,h,i,j,k,l 
19980102,,PLXS,10032,Q,A,,,15.12500,15.00000,15.12500,2 
19980105,,PLXS,10032,Q,A,,,14.93750,14.75000,14.93750,2 
19980106,,PLXS,10032,Q,A,,,14.56250,14.56250,14.87500,2 
20111222,,PCP,63830,N,A,,,164.07001,164.09000,164.12000,1 
20111223,,PCP,63830,N,A,,,164.53000,164.53000,164.55000,1 
20111227,,PCP,63830,N,A,,,165.69000,165.61000,165.64000,1 

выход PCP.csv

a,b,c,d,e,f,g,h,i,j,k,l 
20111222,,PCP,63830,N,A,,,164.07001,164.09000,164.12000,1 
20111223,,PCP,63830,N,A,,,164.53000,164.53000,164.55000,1 
20111227,,PCP,63830,N,A,,,165.69000,165.61000,165.64000,1 

выход PLXS.csv

a,b,c,d,e,f,g,h,i,j,k,l 
19980102,,PLXS,10032,Q,A,,,15.12500,15.00000,15.12500,2 
19980105,,PLXS,10032,Q,A,,,14.93750,14.75000,14.93750,2 
19980106,,PLXS,10032,Q,A,,,14.56250,14.56250,14.87500,2 
Смежные вопросы