"Перегоняем" большой txt (csv) в sql
Ещё одна "сопутствующая" задачка, которую решал сегодня... итак, имеем большой текстовый файл с простейшей структурой, из него надо сделать что-то другое, например, большой SQL-запрос. Можно воспользоваться средством импорта CSV-файлов, встроенным в последние версии утилиты phpMyAdmin, но иногда хочется большего - например, нет возможности обойти ограничения PHP на выделение оперативки.
Быстро решить такую задачу можно с помощью небольшого PHP-скрипта на локалхосте, не нужно только пытаться читать файл функциями вроде file
и file_get_contents
- на сколько-нибудь приличные размерности просто опять-таки не хватит оперативки. Тем более нельзя так делать, если скрипт будет где-то использоваться - "положит" сервер!
Удобное построчное чтение файла без накопления строк в массиве можно делать функцией fgets
, похожей на аналогичную "Сишную", но лишённую её жестких ограничений на размер буфера. Показанный ниже листинг читает построчно текстовый файл с именем, заданным переменной $filename
, разбивает каждую строку по разделителю "|" и формирует в выходном файле (его имя назначается автоматически, папка - текущая) набор многострочных (по $count_new
строк-записей) запросов вида
INSERT INTO data (q,a) VALUES ('вопрос1','ответ1'), ('вопрос2','ответ2'), ... ('вопросN','ответN');
Всё остальное видно по комментариям в листинге.
<?php $handler = $handler2 = null; //Файловые переменных двух файлов - читаемого и записываемого $fbuffer = ''; //Буферная строка для чтения $filename = 'C:/TEMP/questions.txt'; //Имя исходного текстового файла $count_line = 0; //Счётчик прочтианных строк файла $count_new = 10000; //Количество записей в 1 запросе (слишком много может не "потянуть" if (!($handler = fopen($filename, "rb"))) throw new Exception("Cannot open file $filename to read"); //Открываем на чтение файл 1 $path = pathinfo($filename); //Бьём путь исходного файла на части $filename2 = basename($filename,'.'.$path['extension']).'.sql'; //Заменяем расширение на .sql, имя останется то же if (!($handler2 = fopen($filename2, "w"))) throw new Exception("Cannot open file $filename2 to write"); //Открываем на запись файл 2 while(!feof($handler)) { //Читаем файл 1 построчно, ограничений по размеру файла нет! $fbuffer = fgets($handler); //Разбор прочитанной строки: list ($q, $a) = explode ('|',$fbuffer); //Бьём на 2 переменные - $q и $a, разделённые символом | if (!$count_line) //Каждые $count_line строк начинаем новый запрос INSERT fputs ($handler2,'INSERT INTO data (q,a) VALUES'."\n"); if (fputs ($handler2,'(\''.$q.'\',\''.rtrim($a).'\')')===false) //Формируем и пишем строку вида ('$q','$a') throw new Exception("Cannot write to file"); //На всякий случай проверяем, пишутся ли данные $count_line++; if ($count_line < $count_new) { fputs ($handler2,','."\n"); //Каждая пара вставляемых значений будет на новой строке } else if ($count_line == $count_new) { //Если кончился лимит строк очередного запроса - начнём новый $count_line = 0; fputs ($handler2,';'."\n"); } } fputs ($handler2,';'); //Проверьте предпоследнюю строку файла - может быть лишняя запятая fclose ($handler2); fclose ($handler); ?>
23.05.2013, 22:50 [13357 просмотров]