Разделить большой CSV-файл на несколько файлов и сохранить заголовок в каждой части - PullRequest
1 голос
/ 10 марта 2020

Как разделить большой CSV-файл (1 ГБ) на несколько файлов (скажем, одну часть с 1000 строками, 2-ю часть 10000 строк, 3-ю часть 100000 и т. Д. c) и сохранить заголовок в каждой части?

Как мне достичь этого

h1 h2
a  aa
b  bb
c  cc
.
.
12483720 rows

в

h1 h2
a  aa
b  bb
.
.
.
1000 rows

И

h1 h2
x  xx
y  yy
.
.
.
10000 rows

Ответы [ 4 ]

1 голос
/ 11 марта 2020

Еще один awk. Сначала несколько тестовых записей:

$ seq 1 1234567 > file

Затем awk:

$ awk 'NR==1{n=1000;h=$0}{print > n}NR==n+c{n*=10;c=NR-1;print h>n}' file

Объяснено:

$ awk '
NR==1 {           # first record:
    n=1000        # set first output file size and
    h=$0          # store the header
}
{
    print > n     # output to file
}
NR==n+c {         # once target NR has been reached. close(n) goes here if needed
    n*=10         # grow target magnitude
    c=NR-1        # set the correction factor. 
    print h > n   # first the head
}' file

Количество записей:

$ wc -l 1000*
   1000 1000
  10000 10000
 100000 100000
1000000 1000000
 123571 10000000
1234571 total
1 голос
/ 10 марта 2020

Вот небольшая адаптация решения: Разбивать CSV-файлы на более мелкие файлы, но сохраняя заголовки?

awk -v l=1000  '(NR==1){header=$0;next}
                (n==l) { 
                   c=sprintf("%0.5d",c+1); 
                   close(file); file=FILENAME; sub(/csv$/,c".csv",file)
                   print header > file
                   n=0;l*=10
                }
                {print $0 > file; n++}' file.csv

Это работает следующим образом:

  • (NR==1){header=$0;next}: Если запись / строка является первой строкой, сохраните эту строку как заголовок .
  • (n==l){...} : Каждый раз, когда мы пишем запрошенное количество записей / строк, нам нужно начинать запись в новый файл. Это происходит каждый раз n==l и мы выполняем следующие действия:
    • c=sprintf("%0.5d",c+1): увеличиваем счетчик на единицу и печатаем его как 000xx
    • close(file): закрыть файл, который вы только что написали.
    • file=FILENAME; sub(/csv$/,c".csv",file): определить новое имя файла
    • print header > file: открыть файл и записать в него заголовок.
    • n=0: сбросить текущий счетчик записей
    • l*=10: увеличить максимальное количество записей для следующего файла
  • {print $0 > file; n++}: записать записи в файл и увеличить количество записей
0 голосов
/ 10 марта 2020

Следующее bash решение должно работать хорошо:

IFS='' read -r header
for ((curr_file_max_rows=1000; 1; curr_file_max_rows*=10)) {
    curr_file_name="file_with_${curr_file_max_rows}_rows"
    echo "$header" > "$curr_file_name"
    for ((curr_file_row_count=0; curr_file_row_count < curr_file_max_rows; curr_file_row_count++)) {
        IFS='' read -r row || break 2
        echo "$row" >> "$curr_file_name"
    }
}

У нас есть первый уровень итерации, который производит количество строк, которые мы собираемся записать для каждого последующего файла. Он генерирует имена файлов и записывает в них заголовок. Это бесконечный l oop, потому что мы не проверяем, сколько строк имеет вход, и поэтому заранее не знаем, сколько файлов мы собираемся записать, поэтому нам придется break из этого l oop до конца.

Внутри этого l oop мы повторяем второй раз, на этот раз по количеству строк, которые мы собираемся записать в текущий файл. В этом l oop мы пытаемся прочитать строку из входного файла. Если это работает, мы записываем его в текущий выходной файл, если это не так (мы достигли конца ввода), мы break из двух уровней l oop.

Вы можете попробуйте здесь .

0 голосов
/ 10 марта 2020

Вот первый подход:

#!/bin/bash
head -1 $1 >header
split $1 y
for f in y*; do
    cp header h$f
    cat $f >>h$f
done
rm -f header
rm -f y*
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...