training-web.ruГлавнаяКатегорииО насКарта сайтаПоискТёмная тема

Категории

Как разбить большой файл CSV на несколько маленьких файлов BASH

Создано: 27 ноября 2017Автор: Егор Астапов4913 просмотровСложность: легкий

Иногда нужно делать парсинг тяжёлых csv документов. Можно попытаться выполнить подобную задачу средствами PHP. Но как поведёт себя скрипт, если csv - файл весит 100 Мб. Скрипт не отработает. Произойдёт ошибка. Возможно не хватит оперативной памяти сервера. В этом случае есть выход: нужно разделить один большой csv файл на несколько маленьких. Таким образом вы снизите нагрузку на сервер.

Предлагаю вам своё решение. Посмотрите на файл для парсинга. Я не стал делать его большим, но вы должны понимать, что размер файла может быть достаточно большим. Вся сложность в том, что нужно скопировать названия столбцов и несколько раз вставлять в маленькие файлы. Как только большой файл будет поделён на части, то необходимо вставить названия столбцов в самое начало маленьких файлов. Содержимое большого файла должно быть поделено на равные части и записано в маленькие файлы. В этом заключается вся трудность. Если в csv файле нет первой строки с названиями столбцов, то это не правильный по составу файл.


column1;column2;column3;column4;column5;column6;column7;column8
1text1;text1;text1;text1;text1;text1;text1;text1
2text1;text1;text1;text1;text1;text1;text1;text1
3text1;text1;text1;text1;text1;text1;text1;text1
4text1;text1;text1;text1;text1;text1;text1;text1
5text1;text1;text1;text1;text1;text1;text1;text1
6text1;text1;text1;text1;text1;text1;text1;text1
7text1;text1;text1;text1;text1;text1;text1;text1
8text1;text1;text1;text1;text1;text1;text1;text1
9text1;text1;text1;text1;text1;text1;text1;text1
10text1;text1;text1;text1;text1;text1;text1;text1
11text1;text1;text1;text1;text1;text1;text1;text1
12text1;text1;text1;text1;text1;text1;text1;text1
13text1;text1;text1;text1;text1;text1;text1;text1

Теперь рассмотрим сам скрипт sh для разделения csv файла на куски. Перед тем как запустить скрипт создайте папку parts для записи небольших файлов. Логика работы скрипта:

  1. Копирую файл file1.txt. Получается новый файл file2.txt без первой строки. На первой строке у нас были названия столбцов.
  2. Очищаю папку parts от старых файлов
  3. Из оригинального файла file1.txt беру названия столбцов и записываю в переменную header
  4. Разбиваю данные из файл file2.txt на маленькие файлы.
  5. Вывожу данные на экран для понимания работы скрипта
  6. При помощи цикла for добавляю в каждый файл названия столбцов
  7. При помощи цикла for меняю названия файлам file1.txt

#!/bin/bash
#Егор Астапов 2017-11-27

#копируем название столбцов + копирование файла без названия столбцов
sed '1,1d' file1.txt > file2.txt

#очистка папки от старых файлов
rm -rf parts/*

header=$(sed -n '1p;1q' file1.txt)
num_rows=$(cat file2.txt | wc -l)
num_rows=$((num_rows - 1))
num_rows_new=3

cd ./parts
#разбиваем большой csv-файл на части
split -l $num_rows_new ../file2.txt

echo "названия столбцов: "$header
echo "Количество строк (всего): "$num_rows
echo "Количество строк в новом файле: "$num_rows_new

i=1
for file in $(ls)
do
	sed -i -e "1 s/^/$header\n/;"  $file;
	#echo "$file";
	echo $i": "$file" -> file$i.txt"
	
	#переименование файла
	mv $file "file$i.txt"
	i=$(($i+1))
done


#вывод:
#названия столбцов: column1;column2;column3;column4;column5;column6;column7;column8
#Количество строк (всего): 12
#Количество строк в новом файле: 3
#1: xaa -> file1.txt
#2: xab -> file2.txt
#3: xac -> file3.txt
#4: xad -> file4.txt
#5: xae -> file5.txt

Обратите внимание на переменную num_rows_new. Документ будет разбит по количеству строк согласно переменной num_rows_new. В итоге у вас будут масса файлов с одинаковым количеством строк, но последний файл будет отличаться от всех остальных. В нём будет наименьшее количество строк по остаточному принципу: 3 + 3 + 3 + 3 + 1 = 13. В последнем документе будет всего 2 строки. Одна с названиями столбцов, другая с данными. Вы можете не переименовывать файлы. В этом случае получится масса файлов с непонятными названиями: xaa, xab. Я советую вам переименовывать файлы. Так порядка больше. В итоге у вас получится несколько файлов. Я выводу содержимое всех файлов без разрывов.


cat  parts/*

#вывод:
#column1;column2;column3;column4;column5;column6;column7;column8
#1text1;text1;text1;text1;text1;text1;text1;text1
#2text1;text1;text1;text1;text1;text1;text1;text1
#3text1;text1;text1;text1;text1;text1;text1;text1
#column1;column2;column3;column4;column5;column6;column7;column8
#4text1;text1;text1;text1;text1;text1;text1;text1
#5text1;text1;text1;text1;text1;text1;text1;text1
#6text1;text1;text1;text1;text1;text1;text1;text1
#column1;column2;column3;column4;column5;column6;column7;column8
#7text1;text1;text1;text1;text1;text1;text1;text1
#8text1;text1;text1;text1;text1;text1;text1;text1
#9text1;text1;text1;text1;text1;text1;text1;text1
#column1;column2;column3;column4;column5;column6;column7;column8
#10text1;text1;text1;text1;text1;text1;text1;text1
#11text1;text1;text1;text1;text1;text1;text1;text1
#12text1;text1;text1;text1;text1;text1;text1;text1
#column1;column2;column3;column4;column5;column6;column7;column8
#13text1;text1;text1;text1;text1;text1;text1;text1

Я для примера использовал файл с 13 строками (данные). Вы можете сделать большой файл на несколько мегабайт и разделить его на несколько скриптов.

Комментарии

реклама