半夜看见 @Ovear 发文《我是这么设计高性能海量数(ku)据(zi)查询系统的(一)》,留言中@0x0F 也提到加载数据入库的工具。感觉使用SQL语法分析,再提取数据有点麻烦。遂敲了一个简单的数据导入工具,灵活多变。至于强大与否,得看看客的正则水平如何了。

界面:

主界面

原理:

软件工作的时候是这样的。

1.先加载选定的数据文本。逐行读取。

2.每行数据,用正则匹配。如果匹配成功,就开始用匹配到的内容替换软件中的SQL语句中,<match*>部分。

3.执行SQL入库。

例子:

假设我们有一个test.txt的库,内容格式大致如下:

111111 test1
222222 test2
333333 test3
444444 test4
中文测试 abc123

我们要组合成111111--test1这样的格式,导入到 sed_data 库中的test表中的info字段中。

那么我们的正则语句这样写

^(.+?)\s(.+?)$

括号中间是我们要提取的内容。看不明白的朋友上面语句你可以粗浅理解为

“行首(字符串)空格(字符串)行尾”

插入语句这样写:

INSERT INTO `test`(`info`) VALUES('<match1>--<match2>');

语句里面的<match1><match2>是关键。表示正则中的匹配到的第一个括号里面的内容和第二个括号里面的内容。如果你正则有8个() 提取的内容。那么对应的也有 <match1>、<match2>、<match3>...<match8>

以此类推。match注意全部为小写。

在软件中大致如下样子【数据库信息我没填,注意别遗漏了】:

软件介绍

执行后可以看到相关数据库、表、字段正确插入了我们的数据库:

相关数据库、表、字段

再举个例子

假如数据的格式如下:

VALUES 
(1, '个人', 'admin', 'e10adc3949ba59abbe56e057f20f883e', 'admin', '男', 100, 0, 0, 0, '', 10006, 10, 0, '', 0, '', 1343443904, '', 1371490073, '127.0.0.1', -1)

正则大致可以这么写

\((\d*), '(.+?)', '(.+?)', '(.+?)', '(.+?)', '(.+?)'

以上语句我没有真正测试能否匹配出来。可能还需要调试,只是举个例子。如果上面语句正常的话

那么

<match1>=1
<match2>=个人
<match3>=admin
<match4>=e10adc3949ba59abbe56e057f20f883e

我们要入库它用户名到 user_info 表中的 user、pass字段中的话,SQL语句这样写

insert into `user_info`(`user`,`pass`) values('<match3>','<match4>');

如果事前对数据文件,稍作整理的话,应该用这个软件,配合正则能将很多数据入库。

源码预览:

uMain.pas

unit uMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, UniProvider, MySQLUniProvider, DB, MemDS,
  DBAccess, Uni,uThread,PerlRegEx;

type
  TForm1 = class(TForm)
    grpSetting: TGroupBox;
    lblMysqlUser: TLabel;
    lblMySQLPass: TLabel;
    lblMySQLDB: TLabel;
    lblMySQLPort: TLabel;
    lblMySQLHost: TLabel;
    edtMySQLUser: TEdit;
    edtMySQLPass: TEdit;
    edtMySQLDB: TEdit;
    edtMySQLHost: TEdit;
    edtMySQLPort: TEdit;
    conData: TUniConnection;
    SqlData: TUniQuery;
    MySQLUniProvider1: TMySQLUniProvider;
    pnlMain: TPanel;
    lblMatch: TLabel;
    edtMatch: TEdit;
    mmoInsertSQL: TMemo;
    lblInsertSQL: TLabel;
    btnConn: TButton;
    btnSelectFile: TButton;
    btnProc: TButton;
    dlgOpen1: TOpenDialog;
    lblAuthor: TLabel;
    procedure btnConnClick(Sender: TObject);
    procedure btnSelectFileClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnProcClick(Sender: TObject);
  private
    { Private declarations }
  public
    procedure AddData(sContent: string);
  end;

var
  Form1: TForm1;
  sDataPath: string;
  reg: TPerlRegEx;
  sReg,sInertSQL: string;
implementation

{$R *.dfm}

procedure TForm1.AddData(sContent: string);
var
  i: Integer;
  sSQL,sMatch: string;
begin
  reg.Subject := sContent;
  reg.RegEx   := sReg;
  if reg.Match then
  begin
    sSQL := sInertSQL;
    for i := 1 to reg.GroupCount do
    begin
      sMatch := '<match'+IntToStr(i)+'>';
      sSQL   := StringReplace(sSQL,sMatch,reg.Groups[i],[rfReplaceAll]);
    end;
    SqlData.Close;
    SqlData.SQL.Clear;
    SqlData.SQL.Text := sSQL;
    SqlData.ExecSQL;
  end;
end;

procedure TForm1.btnConnClick(Sender: TObject);
begin
  if not conData.Connected then
  begin
    conData.ProviderName := 'MySql';
    conData.Port         := StrToInt(Trim(edtMySQLPort.Text));
    conData.Database     := Trim(edtMySQLDB.Text);
    conData.Username     := Trim(edtMySQLUser.Text);
    conData.Password     := Trim(edtMySQLPass.Text);
    conData.Server       := Trim(edtMySQLHost.Text);
    conData.SpecificOptions.Values['UseUnicode'] := 'True';
    try
      conData.Connect;
    except
      Exit;
    end;
  end;
  if conData.Connected then  ShowMessage('连接成功!')
  else ShowMessage('连接失败!');
end;

procedure TForm1.btnProcClick(Sender: TObject);
var
  myThread: TAddData;
begin
  sReg      := edtMatch.Text;
  sInertSQL := mmoInsertSQL.Text;
  myThread := TAddData.Create(False);
end;

procedure TForm1.btnSelectFileClick(Sender: TObject);
begin
   if dlgOpen1.Execute then
   begin
     sDataPath := dlgOpen1.FileName;
     grpSetting.Caption := '已选择:'+sDataPath;
   end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  reg := TPerlRegEx.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  reg.Free;
end;

end.

线程文件uThread.padd(仅创建一个线程,为了处理数据的时候不卡界面):

unit uThread;

interface

uses
  Classes,SysUtils,Windows;

type
  TAddData = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
  public
    constructor Create(CreateSuspended:Boolean);Overload;
  end;

implementation
uses
  uMain;

constructor TAddData.Create(CreateSuspended: Boolean);
begin
  Inherited Create(CreateSuspended);
  FreeOnTerminate := True;
end;

{ AddData }

procedure TAddData.Execute;
var
  sList: textfile;
  iTime: LongInt;
  lpline: string;
begin
  with Form1 do
  begin
    AssignFile(sList,sDataPath);
    Reset(sList);
    iTime := gettickcount;
    SqlData.Close;
    SqlData.SQL.Clear;
    SqlData.SQL.Text := 'set names utf8';
    SqlData.ExecSQL;
    repeat
      Readln(sList,lpline);
      AddData(lpline);
    until eof(slist);
    iTime := GetTickCount - iTime;
    Caption :=  '完成了!!!'+inttostr(itime div 60000)+'m.';
    CloseFile(sList);
  end;
end;

end.

---------------------------------------------------------------------------------

软件下载(仅供没有编译环境的朋友使用)

链接: http://pan.baidu.com/s/1dDEEDpR 密码: qe7g

为防止被扣黑帽,捆绑什么的,建议大家用源码自己编译,安全放心。

源码版(Delphi2010,组件有UniDAC、PerlReg,自己百度)

链接: http://pan.baidu.com/s/1qWppJCK 密码: dbka

内容很简单,几行代码,随便敲敲,很多没有特别注意的地方,还望海涵,不满意的自己改。

最后不用谢,请叫我雷锋 :)

[原文地址]

相关吐槽:

1#

Sunshie (http://phpinfo.me) | 2014-01-01 08:08

雷峰

2#

寂寞的瘦子 (’) | 2014-01-01 08:16

3#

核攻击 (统治全球,奴役全人类!毁灭任何胆敢阻拦的有机生物!) | 2014-01-01 10:45

方法挺不错的。

4#

点点 (http://t.qq.com/ox_diandi) | 2014-01-01 10:49

雷峰

5#

x1aoh4i (我只能送你们一句话:"乌云自有千种粒,乌云自有黄金屋,乌云自有颜如玉") | 2014-01-01 10:50

不错