#php #csv #fgetcsv
#php #csv #fgetcsv
Вопрос:
У меня есть n файлов csv, которые мне нужно сравнить друг с другом и впоследствии изменить их. Проблема в том, что каждый файл csv содержит около 800 000 строк.
Для чтения файла csv я использую fgetcsv, и он работает хорошо. Получите несколько скачков памяти, но, в конце концов, это достаточно быстро. Но если я попытаюсь сравнить массив друг с другом, это займет целую вечность.
Еще одна проблема заключается в том, что мне приходится использовать foreach для получения данных csv с помощью fgetcsv из-за количества файлов n. В итоге я получаю один сверхбольшой массив и не могу сравнить его с array_diff. Поэтому мне нужно сравнить его с вложенными циклами foreach, а это занимает целую вечность.
фрагмент кода для лучшего понимания:
foreach( $files as $value ) {
$data[] = $csv->read( $value['path'] );
}
мой класс csv использует fgetcsv для добавления выходных данных в массив:
fgetcsv( $this->_fh, $this->_lengthToRead, $this->_delimiter, $this->_enclosure )
Все данные всех файлов csv хранятся в массиве $data. Вероятно, это первая большая ошибка использовать только один массив, но я понятия не имею, как оставаться гибким с файлами, не используя foreach . Я пытался использовать гибкие имена переменных, но и там я застрял 🙂
Теперь у меня есть этот большой массив. Обычно, если я пытаюсь сравнить значения друг с другом и выяснить, существуют ли данные из первого файла во втором файле и так далее, я использую array_diff или array_intersect . Но в этом случае у меня есть только один большой массив. И, как я уже сказал, для запуска foreach требуется время.
Также после всего 3 файлов у меня есть массив с 3 * 800.000 записей. Я думаю, что последние после 10 файлов моя память взорвется.
Итак, есть ли лучший способ использовать PHP для сравнения n очень больших файлов csv?
Комментарии:
1. Обязательно ли это должен быть PHP? Может быть, есть утилита командной строки, которая делает это? Как именно вы сравниваете файлы?
2. Я программист 1980-х годов — тогда мы решили это, используя сортировку, затем некоторую логику для сравнения, затем третий файл с результатом. Несколько раз вы разбивали задание на более мелкие фрагменты, а затем запускали их последовательно. Это не решение, а способ мышления …
3. какой смысл хранить все файлы в одном массиве?
4. Мне нужно сравнить их друг с другом и сгенерировать из них новый массив, который я изменяю и отправляю через API. Итак, в конце концов, мне нужно вернуть его в PHP для API. @Col. как я уже сказал, дело в том, что я понятия не имею, как разделить его и оставаться гибким 🙂
5. Должны ли данные быть в формате CSV? Почему бы не импортировать его в базу данных? Большинство СУБД поддерживают импорт файлов CSV в таблицы без особых трудностей, и как только он будет там, вы можете запускать запросы к данным, чтобы получить сравнение.
Ответ №1:
Используйте SQL
- Создайте таблицу с теми же столбцами, что и ваши файлы CSV.
- Вставьте данные из первого файла CSV.
- Добавьте индексы для ускорения запросов.
- Сравните с другими файлами CSV, прочитав строку и выполнив ВЫБОР.
Вы не описали, как вы сравниваете n файлов, и есть несколько способов сделать это. Если вы просто хотите найти строку, которая находится в A1, но не в A2, …,An, тогда вам просто нужно добавить логический столбец diff в вашу таблицу. Если вы хотите знать, в каких файлах строка повторяется, вам понадобится текстовый столбец или новая таблица, если строка может быть в нескольких файлах.
Редактировать: несколько слов о производительности, если вы используете MySQL (я сейчас мало что знаю о других СУБД).
Вставка строк одна за другой будет слишком медленной. Вы, вероятно, не сможете использовать LOAD DATA
, если не сможете поместить файлы CSV непосредственно в файловую систему сервера БД. Поэтому я думаю, что лучшим решением будет прочитать несколько сотен строк в CSV, а затем отправить запрос с несколькими вставками INSERT INTO mytable VALUES (..1..), (..2..)
.
Вы не можете выдавать a SELECT
для каждой строки, которую вы читаете в других файлах, поэтому вам лучше поместить их в другую таблицу. Затем выполните обновление для нескольких таблиц, чтобы отметить строки, которые идентичны в таблицах t1 и t2: UPDATE t1 JOIN t2 ON (t1.a = t2.a AND t1.b = t2.b) SET t1.diff=1
Может быть, вы могли бы попробовать использовать sqlite. Здесь нет проблем с параллелизмом, и это может быть быстрее, чем модель клиент / сервер MySQL. И вам не нужно много настраивать, чтобы использовать sqlite.
Комментарии:
1. Спасибо. Мне нужно сравнить, находится ли A1 в файле 2/3/4 в любой позиции и так далее. Я думаю, я попробую с временной базой данных
2. Да, я использую LOAD DATA для импорта csv. Он все еще медленный, но пока все в порядке. Спасибо, чувак.