Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Создание sql-скрипта для переноса txt в mysql (http://forum.oszone.net/showthread.php?t=170360)

foxintel 16-03-2010 20:46 1370149

Создание sql-скрипта для переноса txt в mysql
 
Есть txt файл с логами, нужно его перенести в таблицу mysql. Вот пример лога:

03.03.2010/19:03:21 fox/192.168.2.10 http://yandex.ru 7020 7020/493 100% 999 "200 OK gzip"

А вот нужно его поместить в таблицу с колонками (date,time,user,ip,url,size,re,cache,pr,send,otv). Не могу разделить значения с "/". Возможно ли сделать это через sql или нужно дополнительно обрабатывать скриптом?

dmitryst 16-03-2010 22:36 1370214

На perl:
Код:

$date,$time,$user,$ip,$url,$size,$re,$cache,$pr,$send,$otv = split (' ', $stroka);
где $stroka это ваши
Цитата:

Цитата foxintel
03.03.2010/19:03:21 fox/192.168.2.10 http://yandex.ru 7020 7020/493 100% 999 "200 OK gzip" »


foxintel 16-03-2010 23:07 1370240

А как сделать, что бы он читал из файла эти данные?

kim-aa 17-03-2010 16:03 1370773

Цитата:

Цитата dmitryst
$date,$time,$user,$ip,$url,$size,$re,$cache,$pr,$send,$otv = split (' ', $stroka); »

1)
Гм. это по моему просто разбиение строки находящейся в $stroka
разделенной пробелами и рассовывание результатов по скалярным переменным.
Т. к. оператор split всегда возвращает результат как массив, то здесь неявно используется массив по умолчанию @_
Т.е. результаты split присваиваются массиву, а затем элементы массива присваиваются отдельным скалярным переменным.

2)
В качестве зачачи пробела как разделителя, грамотнее использовать не ' ', а следующую конструкцию:
$date,$time,$user,$ip,$url,$size,$re,$cache,$pr,$send,$otv = split /\s+/, $stroka;

3) Простейшее чтение из файла, где имя файла задается в параметрах вызова perl-программы выглядит так:

use strict;

while (<>) {
chomp; # удаление Enter, LF, и подобного
# print "Чо за $_"; Проверка считанного
$date,$time,$user,$ip,$url,$size,$re,$cache,$pr,$send,$otv = split /\s+/, $_;

# SQL вызов

}

# чтение происходит построчно, т. е. файл зараз целиком не считывается, что делает возможным обработку очень больших файлов

# Если имя обрабатываемого файла не указана (нет параметров вызова), то читается стандартный ввод, до Ctrl-Z - win, Ctrl-D - Unix

kim-aa 17-03-2010 16:23 1370796

Так же нужно помнить, что элемент "200 OK gzip" содержит внутри себя пробелы.
Соответственно, нужно вводить более строгие правила, а не просто разбиение по пробельным символам

dmitryst 17-03-2010 16:43 1370813

Цитата:

Цитата kim-aa
это по моему просто разбиение строки находящейся в $stroka »

да.

Цитата:

Цитата kim-aa
элемент "200 OK gzip" содержит внутри себя пробелы »

как я помню, можно просто (...) = split $stroka; , хотя проверить не на чем..

kim-aa 17-03-2010 21:02 1370990

Код (используется ActivePerl 5.10.1)

#! c:\Perl\bin\perl.exe -w
use strict;

my $some_input="03.03.2010/19:03:21 fox/192.168.2.10 http://yandex.ru 7020 7020/493 100% 999 \"200 OK gzip\"";
print "$some_input\n";
my @args=split/\s+/, $some_input;

foreach (@args) {
print "$_ \n";
}

print "---------------------------------------------------------\n";


Результат:

03.03.2010/19:03:21 fox/192.168.2.10 http://yandex.ru 7020 7020/493 100% 999 "200 OK gzip"
03.03.2010/19:03:21
fox/192.168.2.10
http://yandex.ru
7020
7020/493
100%
999
"200
OK
gzip"
---------------------------------------------------------

Цитата:

Цитата dmitryst
как я помню, можно просто (...) = split $stroka; »

Можно. Это просто короткая форма записи
(...) = split /\s+/,$stroka;

foxintel 17-03-2010 21:17 1371003

да это все хорошо, но вот возможно ли еще \ поубирать? А то у меня и так данные в таблицу попадали

kim-aa 17-03-2010 22:12 1371042

Цитата:

Цитата foxintel
да это все хорошо, но вот возможно ли еще \ поубирать? А то у меня и так данные в таблицу попадали »

Не вопрос. Я могу набросать регулярное выражение которое разберет строку.
Только мне нужен пример разбора имеющейся строки такого плана
date,time,user,ip,url,size,re,cache,pr,send,otv

Имеем:
03.03.2010/19:03:21 fox/192.168.2.10 http://yandex.ru 7020 7020/493 100% 999 "200 OK gzip"

Надо:
date=03.03.2010
time=19:03:21
user=fox
ip=192.168.2.10
url=http://yandex.ru

и так до
otv=

2)
Пример соединения с mySQL я приведу попозжа

dmitryst 17-03-2010 23:01 1371078

Цитата:

Цитата kim-aa
используется ActivePerl 5.10.1 »

а почему на перле? Я-то кроме него ничего не знаю, просто предложил как вариант :)

kim-aa 17-03-2010 23:11 1371090

Цитата:

Цитата dmitryst
а почему на перле? Я-то кроме него ничего не знаю, просто предложил как вариант »

Потому что,
1) это единственный язык где регулярные выражения родные, а не прикручены при помощи классов, как в C# - например.
2) Perl создан как обработчик лог-файлов и это он делает гораздо лучше остальных
3) Решил потренироваться, давно не брал в руки шашку :)

=================================

Использование модуля DBI

#! c:\Perl\bin\perl.exe -w
use DBI;


# Заменить dbname, mysqlserver.domain.com, db_username, password на реальные данные
$dbh=DBI->connect('DBI:mysql:dbname:mysqlserver.domain.com:3306', 'db_username', 'password', {RaiseError=>1}) or die "connecting : $DBI::errstr\n";

# 03.03.2010/19:03:21 fox/192.168.2.10 http://yandex.ru 7020 7020/493 100% 999 "200 OK gzip"
# date,time,user,ip,url,size,re,cache,pr,send,otv

# Предполагаем , что переменные уже присвоены
$date='03.03.2010';
$time='19:03:21';
$user='fox';
$ip='192.168.2.10';
$url='http://yandex.ru';
$size=7020;
$re=7020;
$cache=493;
$pr='100%';
$send='999';
$otv='200 OK gzip';


# Конверсии printf
# %g - число
# %d - десятичное целое
# %s строка
# %f - число с плавающей запятой

# Подготовка строки -шаблона SQL оператора
my $sql_fmt= "INSERT INTO tablename VALUES(%s, %s, %s, %s, %s, %d, %d, %d, %s, %d, %s)";

# Формирование SQL-запроса, column_name заменить на реальные имена столбцов

my $sql=sprintf($sql_fmt, $date->column_name, $time->column_name, $user->column_name, $ip->column_name, $url->column_name, $size->column_name, $re->column_name, $cache->column_name , $pr->column_name, $send->column_name, $otv->column_name);

# вызов
$dbh->do ($sql);

$dbh->disconnect;

kim-aa 19-03-2010 22:03 1372747

Разложение строки при помощи регулярных выражений в Perl

#! d:\Perl\bin\perl.exe -w
#use strict;

my $some_input="03.03.2010/19:03:21 fox/192.168.2.10 http://yandex.ru 7020 7020/493 100% 999 \"200 OK gzip\"";
# date,time,user,ip,url,size,re,cache,pr,send,otv

chomp $some_input;
print "$some_input\n";
print "begin---------------------------------------------------------\n";


$some_input =~ m{^([0-9]{1,2}.[0-9]{1,2}.[0-9]{2,4})/([0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2})\b \b(\w+)/([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\b \b(\S+)\b \b(\d+)\b \b(\d+)/(\d+)\b \b(\d+)% \b(\d+)\b (.*)$};

my $date=$1;
my $time=$2;
my $user=$3;
my $ip=$4;
my $url=$5;
my $size=$6;
my $re=$7;
my $cache=$8;
my $pr=$9;
my $send=$10;
my $otv=$11;

print " $date\n $time\n $user\n $ip\n $url\n $size\n $re\n $cache\n $pr\n $send\n $otv\n";



print "end---------------------------------------------------------\n";



Кстати. Хозяйке на заметку :)
Обрабатываемый файл, как я понимаю, представляет собой один из форматов формат apach
В таком формате данные отдает: SQUID и Apach в режиме акселератора.

kim-aa 19-03-2010 22:11 1372753

Вложений: 1
  • ro-0.txt (1.20 KB, скачиваний: 24)
Так как сервер может покоцать код, добавляю как файл

dmitryst 19-03-2010 22:14 1372757

kim-aa, браво!
Цитата:

Цитата kim-aa
1) это единственный язык где регулярные выражения родные, а не прикручены при помощи классов, как в C# - например.
2) Perl создан как обработчик лог-файлов и это он делает гораздо лучше остальных »

согласен на 100%, но надо бы спросить автора темы, может, у него нет возможности на перле скрипты запускать ;)

Цитата:

Цитата kim-aa
В таком формате данные отдает: SQUID »

там еще есть данные по попаданию/не попаданию в кэш, и еще по мелочи.

foxintel 19-03-2010 22:25 1372769

Сейчас бы еще разобраться, как его запустить. Не ругайтесь сильно, но я не знаю как это. У меня есть перл + у меня Windows

kim-aa 19-03-2010 22:32 1372775

1) Скачиваете ActivePerl
2) Скачиваете Notepad++ из приложенного архива, им удобно просматривать код
предварительно выбрав Language\Perl
3) Инсталируете ActivePerl
4) Распаковываете Notepad
5) Скачиваете полученный код и переименовываете его в ro-0.pl и кладете ну скажем в корень D:\

6) Запускаете CMD
7) D:\
8) perl ro-0.pl

Очень помагает наличие FAR или TotalCMD

kim-aa 19-03-2010 22:36 1372779

Склероз, простите

kim-aa 20-03-2010 10:38 1373017

Вариант, возможно более наглядный для новичка.
Сначала производятся замены на Tab как разделитель столбцов.
Потом полученная строка разбирается Split

#! d:\Perl\bin\perl.exe -w
use strict;

my $some_input="03.03.2010/19:03:21 fox/192.168.2.10 http://yandex.ru 7020 7020/493 100% 999 \"200 OK gzip\"";
print "$some_input\n";

#Замена "/ цифра" на "/Tab"
$_=$some_input;
s{/(\d)}{\t$1}g;
my $tmp=$_;

#Замена ":21 fox" на ":21(Tab)fox"
$_=$tmp;
s{(:\d\d) (\w)}{$1\t$2};
$tmp=$_;

#Замена ".xxx http" на ".xxx(Tab)http"
$_=$tmp;
s{(.\d{1,3}) (\w)}{$1\t$2};
$tmp=$_;

#Замена ".ru 7020" на ".ru(Tab)7020"
$_=$tmp;
s{(\S) (\d)}{$1\t$2};
$tmp=$_;

#Замена "7020 7020" на "7020(Tab)7020"
$_=$tmp;
s{(\d) (\d)}{$1\t$2};
$tmp=$_;

#Замена "493 100%" на "493(Tab)100%"
$_=$tmp;
s{(\d) (\d+%)}{$1\t$2};
$tmp=$_;

#Замена "100% 999" на "100%(Tab)999"
$_=$tmp;
s{(\d+%) (\d)}{$1\t$2};
$tmp=$_;

#Замена "999 \" на "999(Tab)\"
$_=$tmp;
s{(\d) }{$1\t};
$tmp=$_;
print "$tmp\n";



my @args=split/\t/, $tmp;

print "begin---------------------------------------------------------\n";
foreach (@args) {
print "$_ \n";
}
print "end---------------------------------------------------------\n";

foxintel 29-03-2010 18:06 1380020

kim-aa Большое спасибо за код. Но как прописать, что бы исходные данне он брал из текстового файла?

kim-aa 29-03-2010 21:09 1380140

foxintel,
Файлик приведите, я на нем и попробую.

И приведу образец кода.

ЗЫ. Будущий урок будет называться дескрипторы в Perl :)

foxintel 07-04-2010 23:21 1387479

Вложений: 1
Вот пример файла))) еще хотел уточнить, это лог файл прокси сервера handycache

kim-aa 17-04-2010 22:55 1395123

1) вот забор данных из файлика
Кстати формат отличается слегка от описанного вами:
- разделение в исходном файле табуляцией
- есть неопознанный "хвост" - пихается в переменную $hz :)


#! d:\Perl\bin\perl.exe -w
#use strict;

# filename
my $full_file_name='d:\home\kim\perl\03.03.2010#18_59_51.txt';

# открытие десктора файла, если не найдено - аварийный выход с сообщением об ошибке
open HANDYCACHE, "< $full_file_name" or die "Cannot open file: $full_file_name. System state: $!";

# построчное чтение, до конца файла
while (<HANDYCACHE>) {

# чтение каждой строки происходит в переменную по умолчанию $_
my $some_input=$_;

#my $some_input='03.03.2010/19:09:27 fox/192.168.2.10 http://www.playground.ru/images/f2.gif 960 960/0 100% 0 "200 OK From Cache (HC)" Н.5';
# date,time,user,ip,url,size,re,cache,pr,send,otv,hz

chomp $some_input;

# отладочный вывод на экран считанной строки
#print "$some_input\n";
#print "begin---------------------------------------------------------\n";

#
#-----------------------------------------03.03.2010------------------------------------------------/19:03:21-----------------------------------------------tab-----------fox/192.168.2.10 ----------------------------------------------------------------------------tab---http://yandex.ru -------7020-------tab-------7020/493 ----------tab--------100% ---tab----999 -------tab--"200 OK From Cache (HC)"-------Н.5;
$some_input =~ m{^([0-9]{1,2}.[0-9]{1,2}.[0-9]{2,4})/([0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2})\b\s+\b(\w+)/([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\b\s+\b(\S+)\b\s+\b(\d+)\b\s+\b(\d+)/(\d+)\b\s+\b(\d+)%\s+\b(\d+)\b\s+(".*")\s+(.*)$};

my $date=$1;
my $time=$2;
my $user=$3;
my $ip=$4;
my $url=$5;
my $size=$6;
my $re=$7;
my $cache=$8;
my $pr=$9;
my $send=$10;
my $otv=$11;
my $hz=$12;

# отладочный вывод на экран разобранной строки
print " $date\n $time\n $user\n $ip\n $url\n $size\n $re\n $cache\n $pr\n $send\n $otv\n $hz\n";

# отладочная заглушка на выполнение одного прохода
#last;

# SQL вызовы







}

print "end---------------------------------------------------------\n";


close HANDYCACHE;


2) С SQL операторами пример приведен в приложенном файлике.
Проверить не могу, за отсутствием MySQL

kim-aa 17-04-2010 22:58 1395124

Вложений: 1
RAR


Время: 16:31.

Время: 16:31.
© OSzone.net 2001-