БлогNot. "Перегоняем" большой txt (csv) в sql

"Перегоняем" большой 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 [13245 просмотров]


теги: textprocessing php mysql форматы

К этой статье пока нет комментариев, Ваш будет первым