2015年8月

首页2015年8月
28
Aug
0

将字符串转换成 UTF8 编码的函数

//函数:
function ToUTF8Encode(str: string): string;
var
b: Byte;
begin
for b in BytesOf(UTF8Encode(str)) do
Result := Format('%s%%%.2x', [Result, b]);
end;

//测试:
var
str: string;
begin
str := '万一';
str := ToUTF8Encode(str);
ShowMessage(str); //%E4%B8%87%E4%B8%80

end;

为 "小月124" 写了个反向函数:

function ToUTF8Decode(const str: string): string;
var
List: TStrings;
tmpStr: AnsiString;
i: Integer;
begin
List := TStringList.Create;
ExtractStrings(['%'], ['%'], PChar(str), List);
SetLength(tmpStr, List.Count);
for i := 0 to List.Count - 1 do
Byte(tmpStr[i+1]) := StrToInt('$' + List[i]);
List.Free;
Result := UTF8Decode(tmpStr);
end;

{ 调用测试 }
procedure TForm1.FormCreate(Sender: TObject);
var
s1: AnsiString;
s2: WideString;
begin
s1 := '%E4%B8%87%E4%B8%80';
s2 := ToUTF8Decode(s1);
ShowMessage(s2); { 万一 }
end;

//===================================================================

D7 早就支持 utf8string 了,utf8string string widestring 代表 3 种编码的字符串。

到了 XE7 ,就只有 string 了,代表 unicode 其他编码都使用 tbytes 保存。转换用 tencdoing.ansi tencoding.utf8 tencdoing.unicode 就可以了。非常的方便。

//===================================================================
TArrChar = array of Byte;
class function TShouQianBa.StrToByteArr(aStr: string): TArrChar;
var
b:Byte;
bys:TArrChar;
begin
//tencoding.utf8.Convert( tencdoing.unicode
for b in BytesOf(UTF8Encode(astr)) do
begin

SetLength(bys,Length(bys) + 1);
bys[Length(bys) - 1] := b;

end;
Result := bys;
end;

28
Aug
0

执行计划及Sql查询优化知识点

--1.0
--显示有关由Transact-SQL 语句生成的磁盘活动量的信息
--SET STATISTICS IO ON
--关闭有关由Transact-SQL 语句生成的磁盘活动量的信息
--SET STATISTICS IO OFF
--显示[返回有关语句执行情况的详细信息,并估计语句对资源的需求]
--SET SHOWPLAN_ALL ON
--关闭[返回有关语句执行情况的详细信息,并估计语句对资源的需求]
--SET SHOWPLAN_ALL OFF
--显示有关由Transact-SQL 语句执行速度
--SET STATISTICS time ON
--清空占用的缓存
--DBCC DROPCLEANBUFFERS;

--DBCC FREESYSTEMCACHE('ALL');

--请记住:SET STATISTICS IO 和 SET SHOWPLAN_ALL 是互斥的。

--执行的扫描次数;
--从数据缓存读取的页数;
--从磁盘读取的页数;
--为进行查询而放入缓存的页数
--重要:如果对于一个SQL查询有多种写法,那么这四个值中的逻辑读(logical reads)决定了哪个是最优化的。

--小结
--当你构建SQL语句时,按Ctrl+L就可以看到语句是如何执行,是用索引扫描还是表扫描?
--通过SET STATISTICS IO ON 来查看逻辑读,完成同一功能的不同SQL语句,逻辑读越小查询速度越快

--2.0
--查询一张表的记录数
--SELECT ROWS FROM SYSINDEXES WHERE ID = OBJECT_ID('T_UserInfo') AND INDID = 1

--统计了前10个最费时间的查询
SELECT TOP ( 10 )
SUBSTRING(ST.text, ( QS.statement_start_offset / 2 ) + 1,
(( CASE statement_end_offset WHEN -1 THEN DATALENGTH(st.text) ELSE QS.statement_end_offset END - QS.statement_start_offset ) / 2 ) + 1)
AS statement_text ,
execution_count ,
total_worker_time / 1000 AS total_worker_time_ms ,
( total_worker_time / 1000 ) / execution_count AS avg_worker_time_ms ,
total_logical_reads ,
total_logical_reads / execution_count AS avg_logical_reads ,
total_elapsed_time / 1000 AS total_elapsed_time_ms ,
( total_elapsed_time / 1000 ) / execution_count AS avg_elapsed_time_ms ,
qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
ORDER BY total_worker_time DESC

--查询可以告诉你在SQL Server里每个数据库有多少空间被浪费
SELECT
DB_NAME(database_id),
SUM(free_space_in_bytes) / 1024 AS 'Free_KB'
FROM sys.dm_os_buffer_descriptors
WHERE database_id <> 32767
GROUP BY database_id
ORDER BY SUM(free_space_in_bytes) DESC

27
Aug
0

泛型容器单元

Delphi 2009 新增了泛型容器单元: Generics.Collections, 同时还有一个 Generics.Defaults 单元做支持.

Generics.Collections 包含了以下实用类:
TList<T>
TQueue<T>
TStack<T>
TDictionary<TKey,TValue>
TObjectList<T>
TObjectQueue<T>
TObjectStack<T>

TObjectDictionary<TKey,TValue>

有了以上泛型的容器, 恐怕 Classes.TList 和 Contnrs 单元下的 TObjectList 等系列容器也就只为兼容存在了.

Generics.Collections.TList<T> 既然是泛型的, 那肯定应该容得下字符串列表, 本例就依此测试吧.

26
Aug
0

dll的两种调用方式

unit TestDLL_Pas;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)

 Button1: TButton;
 Edit1: TEdit;
 Edit2: TEdit;
 Button2: TButton;
 Edit3: TEdit;
 Edit4: TEdit;
 CheckBox1: TCheckBox;
 Button3: TButton;
 Edit5: TEdit;
 Edit6: TEdit;
 Edit7: TEdit;
 Edit8: TEdit;
 Button4: TButton;
 CheckBox2: TCheckBox;
 Button5: TButton;
 Button6: TButton;
 Edit9: TEdit;
 procedure Button1Click(Sender: TObject);
 procedure Button2Click(Sender: TObject);
 procedure Button3Click(Sender: TObject);
 procedure Button4Click(Sender: TObject);
 procedure Button5Click(Sender: TObject);
 procedure Button6Click(Sender: TObject);

private

 { Private declarations }

public

 { Public declarations }

end;

var
Form1: TForm1;
_DLLMoudle: THandle;

//动态调用方式、先定义函数、后面在通过Button5Click过程调入个函数接口地址

_GetPassWord:function (Pass:string):string;stdcall;
_CheckPassWord:Function(SourcePass:string;EncryPass:string):boolean;stdcall;
_StrEncrypt:Function(s: string; key: word): string;StdCall;
_StrDecrypt:Function(s: string; key: word): string;StdCall;
_GetRegistCode:Function(Pass:string):String;StdCall;
_CheckRegistCode:Function(CompanyName,RegistCode:string):Boolean;StdCall;

//下面为静态调用方式

function GetPassWord(Pass:string):ShortString;stdcall;external 'MyHRDLL.dll';
function CheckPassWord(SourcePass,EncryPass:string):Boolean;stdcall;external 'MyHRDLL.dll';
function StrEncrypt(s: string; key: word): ShortString;stdcall;external 'MyHRDLL.dll';
function StrDecrypt(s: string; key: word): ShortString;stdcall;external 'MyHRDLL.dll';
function GetRegistCode(Pass:string):ShortString;stdcall;external 'MyHRDLL.dll';
function CheckRegistCode(CompanyName,RegistCode:string):Boolean;stdcall;external 'MyHRDLL.dll';

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
Edit2.Text := GetPassWord(Edit1.Text);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
_bool :Boolean;
begin
_Bool := CheckRegistCode(Edit3.Text,Edit4.Text);
CheckBox1.Checked := _bool;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
edit6.Text := GetRegistCode(edit5.Text);
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
CheckBox2.Checked := CheckPassWord(Edit7.Text,edit8.Text);
end;

procedure TForm1.Button5Click(Sender: TObject);
begin

try
  _DLLMoudle := Loadlibrary('MyHRDLL.dll');
  ShowMessage('初始化成功!!!');
except
  ShowMessage('初始化失败!!!');
  Exit;
end;
if _DLLMoudle > 32 then begin
   Try
     @_GetPassWord:=GetProcAddress(_DLLMoudle,'GetPassWord');              //打开串口
    @_CheckPassWord:=GetProcAddress(_DLLMoudle,'CheckPassWord');            //关闭串口
    @_StrEncrypt:=GetProcAddress(_DLLMoudle,'StrEncrypt');            //对卡号冲值
    @_StrDecrypt:=GetProcAddress(_DLLMoudle,'StrDecrypt');                //删除卡号
    @_GetRegistCode:=GetProcAddress(_DLLMoudle,'GetRegistCode');      //终端机清除刷卡记录
    @_CheckRegistCode:=GetProcAddress(_DLLMoudle,'CheckRegistCode');            //
     ShowMessage('DLL装载成功.............');
   Except
     ShowMessage('出错!!DLL打开失败!!不能做其他操作!!');
   End
end;

end;

procedure TForm1.Button6Click(Sender: TObject);
begin
edit9.Text := FormatDateTime('MMDDHHNN',Now);
end;

end.

25
Aug
0

PChar和Char数组的比较

  string和Char数组都是一块内存, 其中存放连续的字符. string保存具体字符的内存对用户是透明的, 由Delphi管理它的分配, 复制和释放, 用户不能干预(其实也可以, 不过是通过 非法途径). Char数组就不必说了吧?
  PChar是一个指针, 它的大小只有32位. 定义时由Delphi自动填0. 要将PChar作为字符串使用的话必须自己分配内存用完必须自己释放. PChar型字符串由#0表示字符串结尾
  Delphi所提供的相关PChar字符串的操作都是判断#0来决定字符串的结尾的。因为PChar是指针,所以它能指向任何地方(也就是说它不一定非要指向字符串不可). 把一个String赋值给PChar只是将String中保存具体字符串的内存的地址给PChar变量. 当然也可以把Char数组第一个元素的地址给PChar. 至于 哪个占用内存小, Char数组<Char(指分配过字符串的)<string(除了具体字符串外还 包含字符串长度)
  如果空字符串那么PChar<String<array [0..n] of Char
  从速度来说毫无疑问string最慢, 例如:
  作为参数传递(非var调用时)给过程时string将整个字串的副本传递过去, PChar将指针本身的副本传递过去(32位), Char数组和PChar一样, 传递的是第一个元素的地址副本.不过就灵活性来说string最高, 而且Delphi支持的函数最多. 另外可以将String作为Buffer使用(因为它当中可以包含字符0).


  在Delphi2.0以后的版本中,string分两种,一种是与Pascal传统string相兼容,叫ShortString, 它的存储结构如下:

 +---------------------+    
 | 1Byte |    字符串内容 | 
 +---------------------+ 
 0         1 ...... 
  其中第一个字节为字符串的长度。 
  所以ShortString所能包括的字符串长度不能大于255。

  另一种是叫长字符串AnsiString,它就是一个指向字符串的指针,不过具体的存储有些特别。它的存储结构如下:

+-----------------------+ 
| 4B | 4B |    字符串内容 | 
+-----------------------+ 
-8     -4     0    ...... 

  其中,AnsiString指向字符串第一个字符,nbsp;
  在第一个字符的反方向第1到第4的4个字节表示字符串长度,第5到第8的4个字节表字符串被引用的次数。

  pchar就是纯指向字符串(#0字符结尾)的指针,与C语言中的char *是一样的。
  char数组也是指向字符串的指针,它与pchar的区别在于:

    1.char数组(均指非动态数组)一旦定义好,它的长度就固定了; 
    2.char数组的地址是常量,不能另赋其它值,不能象pchar一样, 

  如: sPchar:pchar; sArray1,sArray2:array[0..80]of char;

       sPChar:=sArray2; sPChar;=sArray1; 

  但不能sArray2:=sArray1;
  char数组就相当于const char *

  要说速度最快当然是纯指针操作的pchar与char数组最快啦,所谓占内存最少,效率更高,不知老兄你想进行什么方面的应用,一般对string,pchar或char数组,不用考虑这些。

  对编程而言,如果在Delphi或C++Builder中使用,可尽量使用AnsiString, Borland公司对它已经进行了非常完美的内部处理,使用非常方便。
  如果涉及到Windows API或混合编程等,接口部分一般使用pchar。

  char数组使用的比较少了,因为多数可以用char数组的地方,现在比较流行的作法是定义一个ansistring, 再用setlength来设定它的长度。


  三、字符串string 字符数组与指向字
  符串的指针pchar的区别与联系
  这3者的基本概念相同,但有一些非常细微的差别,在编程时稍不注意就会出错,需高度重视。
  1、使用指向字符串的指针,如果不是以0结尾,运行时就会出现错误。为了避免这种错误,需要在字符串结尾人工加入0 即char(0),或用strpcopy函数在字符串结尾自动加0。
  例1: 指向字符串的指针,如果不是以0结尾,运行时会出现错误:
  {s[0]=3 s[1]='n' s[2]='e' s[3]='w'}
  var

   s:string; 
         p:pchar; 

  begin

   s:='new'; 
     label1.caption:=s; {new} 
     label2.caption:=intTostr(integer(s[0]));{3是字符串的长度} 
   p:=@s[1];{不是以0结尾,莫用pchar型指针} 

   label3.caption:=strpas(p); {运行时出现错误}
  end;

  例2:在字符串结尾人工加入0即char(0),可使用指向字符串的指针。
  {s[0]=4 s[1]='n' s[2]='e' s[3]='w' s[4]=0;}
  {p-->'new'}
  var

          s:string; 
          p:pchar; 

  begin

   p:=@s[1]; 
   s:='new'+char(0); {以0结尾,可用pchar型指针} 
   label1.caption:=strpas(p); {new}

注意:

procedure GetMem(var P: Pointer; Size: Integer);
//分配动态内存
function StrPas(const Str: PChar): string;
//将PChar转换为String