[转载]Android JAVA 语言基础例子代码

mikel阅读(925)

[转载]Android JAVA 语言基础例子代码 – Thinker – 博客园.

Android的界面一般都是java开发的,因此对于c++,.net人员来说理解和编写有一个适应过程,最近参考了一下资料,把这些涉的一些java基础使用以例子代码的形式总结起来,记录了这个平台的熟悉过程。

文件目录(涉及了java的一些主要语法)

AnnotDefine.java
AnnotDemo.java             ClassDemo.java
CodeResource_en_US.java    Collection.java
demo.java                  example_en_US.properties
Generic.java               InitDemo.java
IO.java                    LocalResource.java
Nest.java                  PrefsDemo.java
ThreadDemo.java

下载地址:

http://cid-56b433ad3d1871e3.office.live.com/self.aspx/.Public/AndroidJava.rar

至于JAVA和C#的语法区别,可以参考一个有意思的网站

http://www.harding.edu/fmccown/java_csharp_comparison.html

以下是一些简要的说明(JDK),具体的使用和一些说明参考以上的例子

Collections Framework

包:java.util

接口

核心和层次关系

Iterable, Collection, List, Set, SortedSet, Queue, Map, and SortedMap.

image

实现类

实现类约定:

Abstract开头的是抽象类,用于减少多个实现的代码重复

具体的类以接口的名字结尾,如ArrayList实现的事List接口

如下是JDK中的实现类列表

AbstractCollection, AbstractList, AbstractQueue, AbstractSequentialList, AbstractSet,

ArrayBlockingQueue, ArrayDeque, ArrayList, AttributeList, ConcurrentLinkedQueue, ConcurrentSkipListSet, CopyOnWriteArrayList, CopyOnWriteArraySet, DelayQueue, EnumSet, HashSet, JobStateReasons, LinkedBlockingDeque, LinkedBlockingQueue, LinkedHashSet, LinkedList, PriorityBlockingQueue, PriorityQueue, RoleList, RoleUnresolvedList, Stack, SynchronousQueue, TreeSet, Vector

工具类

数组和容器的遍历方法

Collection<String> col = …

Iterator iter = col.iterator();

while (iter.hasNext())

System.out.println(iter.next());

for (String s: col)

System.out.println(s);

嵌套类型Nested Type

There are four kinds of nested classes: static member classes, nonstatic member classes, anonymous classes, and local classes. The latter three categories are known as inner classes.

注释类型annotations

java.lang

Deprecated
Override
SuppressWarnings

java.lang.annotation

Documented
Inherited
Retention
Target

javax.annotation

Generated
PostConstruct
PreDestroy
Resource
Resources

[转载]为Android安装BusyBox —— 完整的bash shell

mikel阅读(995)

[转载][Android] 为Android安装BusyBox —— 完整的bash shell – 木乃猫的学习笔记 – 博客园.

大家是否有过这样的经历,在命令行里输入adb shell,然后使用命令操作你的手机或模拟器,但是那些命令都是常见Linux命令的阉割缩水版,用起来很不爽。是否想过在Android上使用较完整 的shell呢?用BusyBox吧。不论使用adb连接设备使用命令行还是在手机上直接用terminal emulator都可以。

一、什么是BusyBox ?

BusyBox 是标准 Linux 工具的一个单个可执行实现。BusyBox 包含了一些简单的工具,例如 cat 和 echo,还包含了一些更大、更复杂的工具,例如 grep、find、mount 以及 telnet。有些人将 BusyBox 称为 Linux 工具里的瑞士军刀.简单的说BusyBox就好像是个大工具箱,它集成压缩了 Linux 的许多工具和命令。(摘自百度百科)

二、在Android上安装BusyBox

准备:

1. 下载BusyBox的binary,打开这个地址 http://www.busybox.net/downloads/binaries ,选择最新版本,然后下载对应你的设备架构的版本,这里我下载了busybox-armv6l,下面将以这个文件名为示例。

2. 需要有一个命令行的环境,在电脑上使用adb或在手机上使用terminal emulator。

3. 连接手机和电脑,手机的USB Mode设置成None(仅充电),并且开启USB调试模式。

安装:

1. 将busybox-armv6l重命名为busybox

2. 将busybox传入手机的SD卡,可以使用下面的命令或自己想其他办法。

打开terminal(Linux,Mac)或cmd(Windows)

adb push ~/Desktop/busybox /mnt/sdcard

其中的~/Desktop请根据自己的情况替换成正确的路径

3. 输入以下命令,为了在/system目录写入文件

adb shell
su
mount -o remount,rw -t yaffs2 /dev/block/mtdblock3 /system

使用 ls 检查一下 /system 里是否有 xbin 目录,没有的话输入 mkdir xbin 创建,因为本示例是要把busybox安装到 /system/xbin 。

4. 复制 busybox 文件到 /system/xbin,并为其分配“可执行”的权限

cp /mnt/sdcard/busybox /system/xbin
chmod 755 busybox

5. 这时就可以使用 busybox 的命令了,例如以前没有清屏的clear命令,现在只需输入 busybox clear 就可以实现清屏功能,使用完整版的 ls 只需输入 busybox ls 。

但是每次前面都加上个busybox太麻烦了,所以我们还要继续完成安装。

在 /system/xbin 下输入

busybox --install .

如果想安装到别的目录,则把点替换成别的路径。

至此就安装完成了,比较一下原来的 ls 命令和 busybox 里的 ls 命令。

常见错误:

1. 如果安装时出现这样的错误,

busybox: /bin/zcat: No such file or directory

busybox: /sbin/zcip: Invalid cross-device link

说明没有输入安装路径,正确的示例 busybox –install /system/xbin

2. 如果出现这样的错误,

cp: /system/xbin/busybox: Read-only file system

说明没有正确输入上面第三步的mount命令。

小技巧:

1. busybox 里有 ash 和 hush 还有 sh 这几种 shell,在命令行输入 ash 或 hush,可以像在 bash 里那样,通过按上下键选择刚才输入的命令。

2. android系统本身就有ls命令,busybox里也有ls,输入ls时调用的是android的ls,那么想用busybox的ls就要每次都在前面加个busybox吗?不用,使用alias命令可以搞定。

alias ls='busybox ls'

同样的,cp、mv等二者都有的命令都可以这样搞定。也可以通过修改 /init.rc 来解决。

[转载]推荐14款强大的HTML5素描及绘图工具

mikel阅读(1069)

[转载]推荐14款强大的HTML5素描及绘图工具 – 梦想天空 – 博客园.

我们知道,素描是设计师工作流程中的一个重要环节。本文收集了一些借助 JavaScript和HTML5 Canvas开发的素描工具,这些工具表明,HTML5的确是一个令人兴奋的标记语言。如果你发现了新的基于HTML5 Canvas开发的绘图工具,欢迎在这里与大家分享。

1. Mr. Doob’s Harmony

HTML5 Sketching Tools Every Designers Must Know

如果你喜欢涂鸦,可以试试这款工具,它有各种各样的画笔可用于绘图。

2. Sketch

HTML5 Sketching Tools Every Designers Must Know

一款叫Hakim El Hattab的人开发的一款素描工具,可绘制三维图案。

3. deviantMuro

HTML5 Sketching Tools Every Designers Must Know

一款非常好的用于素描及绘画的工具,有很多强大的功能。

4. Sketchy Structures

HTML5 Sketching Tools Every Designers Must Know

这款绘图工具可以绘制出一些非常特别的场景。

5. Multi-User Sketchpad

HTML5 Sketching Tools Every Designers Must Know

一款支持多人同时在线绘画的工具。

6. Sketchpad

HTML5 Sketching Tools Every Designers Must Know

一款非常棒的绘画工具,看起来很炫啊。

7. Bezier Sketching

HTML5 Sketching Tools Every Designers Must Know

贝塞尔素描工具,最大的特色是定义路径。

8. Gartic Canvas Sketch

HTML5 Sketching Tools Every Designers Must Know

另一款基于WEB的绘图工具。

9. Spirograph

HTML5 Sketching Tools Every Designers Must Know

可以画出很炫的圆形图案的工具。

10. Bomomo

HTML5 Sketching Tools Every Designers Must Know

一款让人惊叹的绘图工具,想了解更多,请访问Bomomo’s gallery.

11. Internet Graffiti Board

HTML5 Sketching Tools Every Designers Must Know

每个人都可以使用的涂鸦板,即时保存和发布。

12. Pschiiit

HTML5 Sketching Tools Every Designers Must Know

这是一个网络涂鸦板的增强版,图案以多边形形式存储在PostGreSQL数据库中。

13. physicSketch

HTML5 Sketching Tools Every Designers Must Know

你在画布上绘制的图形会以重力效应运动。

14. Zwibbler

HTML5 Sketching Tools Every Designers Must Know

另一款基于HTML5 Canvas开发的绘图程序。

(编译来源:梦想天空 原文来自:HTML5 Sketching Tools Every Designers Must Know

[转载]如何使用C#实现网易博客中圈子用户数据的采集

mikel阅读(1130)

[转载]如何使用C#实现网易博客中圈子用户数据的采集 – wuhuacong(伍华聪)的专栏 – 博客园.

新浪博客,网易博客,都是博客中的佼佼者,其中网易提供的圈子信息,更胜一筹,使得一般用户能够通过访问圈子进入相关的群组,或者获取相关圈子用户 的信息等,以实现各种精准营销的目的。虽然新浪遮遮掩掩不提供圈子的相关信息,相对而言,网易博客提供圈子,能够使得更多的人、更多的程序支持,推高博客 的知名度及实用性。网易博客可以通过地址http://q.163.com/ 访问,它是经过两级分类的,如下所示。

点击分类进入即可查看到每个子分类都有很多圈子,圈子累死QQ的群组,是某一兴趣团体的博客,里面收集很多相关的资料及信息,如下所示:

这里不关心圈子的有哪些宝贵学习资料,我更关心的是这些圈子的用户如何采集出来,由于用户都是网易的用户,因此他们一个账户就会对应一个账号,有163.com,163.net,yeah.net,126.com等等的,我们先看看圈子的用户信息是如何显示的。

我们看到上图里面圈子的信息是一个列表,有的圈子多,有的圈子少,不过他们的名称中都会关联一个博客地址的,由于博客地址和邮件地址有一一对应关系,因此可以获取对应的邮件信息,这就是我们所要的重要信息。

下面用一个程序来介绍如何采集圈子的分类、圈子数据以及圈子用户资料信息,测试的程序如下所示:

下面我们来看看按钮”刷新分类数据“的实现代码,主要是获取圈子大类、圈子子类以及保存数据操作,代码如下所示:

private void btnRefreshCategory_Click(object sender, EventArgs e)
{
string url = http://q.163.com/;
string mainTypeReg = <div\\s*style=\”font-size:14px;\”><b><a\\s*?href=\”(?<value>.*?)\”>(?<key>.*?)</a></b></div>;
string subTypeReg = <div\\s*class=\”left\”><a\\s*href=\”(?<value>.*?)\”>(?<key>.*?)</a></div> ;

#region 取得大类

httpHelper.Encoding = Encoding.Default;
string content = httpHelper.GetHtml(url);
Regex re
= new Regex(mainTypeReg, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace);
Match mc
= re.Match(content);
Dictionary
<string, string> typeDict = new Dictionary<string, string>();
if (mc.Success)
{
MatchCollection mcs
= re.Matches(content);
foreach (Match me in mcs)
{
string strKey = me.Groups[key].Value;
string strValue = me.Groups[value].Value;
//截取连接前面部分作为大类标识
string newValue = strValue.TrimEnd(/);
int eIndex = newValue.LastIndexOf(/);
newValue
= newValue.Substring(0, eIndex) + /;

if (!typeDict.ContainsKey(strKey))
{
typeDict.Add(strKey, newValue);
}
}
}
#endregion

#region 取得子类
Dictionary
<string, CircleSubTypeInfo> circleDict = new Dictionary<string, CircleSubTypeInfo>();
re
= new Regex(subTypeReg, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace);
mc
= re.Match(content);
if (mc.Success)
{
MatchCollection mcs
= re.Matches(content);
foreach (Match me in mcs)
{
string strKey = me.Groups[key].Value;
string strValue = me.Groups[value].Value;
//截取连接前面部分作为大类标识
string typeValue = strValue.TrimEnd(/);
int eIndex = typeValue.LastIndexOf(/);
typeValue
= typeValue.Substring(0, eIndex) + /;

if (!circleDict.ContainsKey(strKey))
{
CircleSubTypeInfo info
= new CircleSubTypeInfo();
info.Name
= strKey;
info.LinkUrl
= strValue;
info.TypeUrlValue
= typeValue;

circleDict.Add(strKey, info);
}
}
}
#endregion

#region 保存数据
Database db
= DatabaseFactory.CreateDatabase();
DbCommand command
= null;
string SQL = “”;

foreach (string key in typeDict.Keys)
{
SQL
= string.Format(Insert into CircleType(TypeName, TypeValue) values(‘{0}’, ‘{1}’) , key, typeDict[key]);
command
= db.GetSqlStringCommand(sql);
db.ExecuteNonQuery(command);
}

foreach (string key in circleDict.Keys)
{
CircleSubTypeInfo info
= circleDict[key];
sql
= string.Format(Insert into CircleSubType(SubTypeName, LinkUrl, TypeUrlValue) values(‘{0}’, ‘{1}’, ‘{2}’) , info.Name, info.LinkUrl, info.TypeUrlValue);
command
= db.GetSqlStringCommand(sql);
db.ExecuteNonQuery(command);
}
#endregion

this.lblTips.Text = 获取分类操作完成;

}


其中主要是采用了正则表达式来对获取的内容进行处理,然后整理出来相关的分类数据放到数据库中,以便获取圈子用户信息作准备。

有了圈子分类信息,我们第二步骤就是看如何获取圈子数据,然后才能通过圈子的唯一ID获取圈子的用户资料,这步也是必须的,获取圈子资料是比较复杂的,需要组装较多的参数获取资料,部分代码如下所示。

foreach (string key in urlDict.Keys)
{
string keyNumberReg = /mapCircleList/(?<d1>[1-9]\\d*)/(?<d2>[1-9]\\d*)*/(?<d3>[1-9]\\d*)/;
Regex re
= new Regex(keyNumberReg, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace);

LogTextHelper.WriteLine(string.Format(正在处理类型:{0}, urlDict[key]));
cookie
= new System.Net.CookieContainer();

string urlKey = key;
Match mc
= re.Match(urlKey);
string d1 = mc.Groups[d1].Value;
string d2 = mc.Groups[d2].Value;
string d3 = mc.Groups[d3].Value;
int pageSize = 30;

urlKey = urlKey.Trim(/);//清除前后的/字符
string url = http://q.163.com/dwr/call/plaincall/CircleMainpageBean.getCircleByType2IdInMemberOrder.dwr;
//string refUrl = “http://q.163.com/mapCircleList/2/11/48/?fromCircleCircleMap“;
string refUrl = string.Format(http://q.163.com/{0}/?fromCircleCircleMap, urlKey);
#region 内容正则表达式
StringBuilder circleReg
= new StringBuilder();
circleReg.Append(
s[0-9]\\d*.circleId=(?<circleId>[0-9]\\d*[^;]));
circleReg.Append(
.*?s[0-9]\\d*.circleType1Str=\”(?<circleType1Str>.*?)\”);
circleReg.Append(
.*?s[0-9]\\d*.circleType2Str=\”(?<circleType2Str>.*?)\”);
circleReg.Append(
.*?s[0-9]\\d*.createDateStr=\”(?<createDateStr>.*?)\”);
circleReg.Append(
.*?s[0-9]\\d*.creatorId=(?<creatorId>[0-9]\\d*[^;]));
circleReg.Append(
.*?s[0-9]\\d*.creatorName=\”(?<creatorName>.*?)\”);
circleReg.Append(
.*?s[0-9]\\d*.creatorSpaceUrl=\”(?<creatorSpaceUrl>.*?)\”);
circleReg.Append(
.*?s[0-9]\\d*.description=\”(?<description>.*?)\”);
circleReg.Append(
.*?s[0-9]\\d*.joinDeclaration=\”(?<joinDeclaration>.*?)\”);
circleReg.Append(
.*?s[0-9]\\d*.linkImgUrl=\”(?<linkImgUrl>.*?)\”);
circleReg.Append(
.*?s[0-9]\\d*.memberNum=(?<memberNum>[0-9]\\d*[^;]));
circleReg.Append(
.*?s[0-9]\\d*.name=\”(?<name>.*?)\”);
circleReg.Append(
.*?s[0-9]\\d*.urlName=\”(?<urlName>.*?)\”);
circleReg.Append( .*?s[0-9]\\d*.visitNum=(?<visitNum>[0-9]\\d*[^;]));


通过组装参数数据,然后获取页面数据,对页面数据进行分析即可,主要代码如下所示:

if (mc.Success)
{
string message = string.Format(正在处理类型{0}:{1}, 第{2}次数据, 共处理了{3}, urlDict[key], url, i + 1, j);
CallCtrlWithThreadSafety.SetText(
this.lblTips, message, this);
Application.DoEvents();
Thread.Sleep(
10);

MatchCollection mcs = re.Matches(content);
foreach (Match me in mcs)
{
#region MyRegion
j
++;

int memberNum = 0;
try
{
memberNum
= Convert.ToInt32(me.Groups[memberNum].Value);
}
catch { }
if (memberNum < 50)
{
flag
= false;
break;
}

sql
= string.Format(@”insert into Circle(circleId,circleType1Str,circleType2Str,createDateStr,creatorId,
creatorName,creatorSpaceUrl,description,joinDeclaration,linkImgUrl,memberNum,name2,urlName,SubTypeName)
values(‘{0}’,'{1}’,'{2}’,'{3}’,'{4}’,'{5}’,'{6}’,'{7}’,'{8}’,'{9}’,'{10}’,'{11}’,'{12}’,'{13}’)
, me.Groups[circleId].Value,
UnicodeHelper.UnicodeToString(me.Groups[
circleType1Str].Value.Replace(, “”)), UnicodeHelper.UnicodeToString(me.Groups[circleType2Str].Value.Replace(, “”)),
me.Groups[
createDateStr].Value, me.Groups[creatorId].Value, UnicodeHelper.UnicodeToString(me.Groups[creatorName].Value),
me.Groups[
creatorSpaceUrl].Value, UnicodeHelper.UnicodeToString(me.Groups[description].Value.Replace(, “”)), UnicodeHelper.UnicodeToString(me.Groups[joinDeclaration].Value.Replace(, “”)),
me.Groups[
linkImgUrl].Value, me.Groups[memberNum].Value, UnicodeHelper.UnicodeToString(me.Groups[name].Value.Replace(, “”)), me.Groups[urlName].Value, urlDict[key]);
command
= db.GetSqlStringCommand(sql);
try
{
db.ExecuteNonQuery(command);
}
catch (Exception ex)
{
LogTextHelper.WriteLine(sql);
LogTextHelper.WriteLine(ex.ToString());
}

message = string.Format(正在处理{0}:{1} 正在写入数据{2}次, urlDict[key], url, j);
CallCtrlWithThreadSafety.SetText(
this.lblTips, message, this);
Application.DoEvents();
Thread.Sleep(
10);

#endregion
}
}
else
{
flag
= false;//没有匹配就停止
break;
}

}

构造获取圈子用户信息也是比较复杂的一个过程,需要组装更多的参数来获取相关的数据,部分主要实现代码如下所示:

httpHelper = new HttpHelper();
httpHelper.Encoding
= Encoding.Default;
cookie
= new CookieContainer();
Regex re
= null;
Match mc
= null;
int pageSize = 30;
string url = http://q.163.com/dwr/call/plaincall/CircleBean.getNewCircleUsers.dwr;

foreach (string key in circlelDict.Keys)
{
string circleId = key;
string urlName = circlelDict[key];
string refUrl = string.Format(http://q.163.com/{0}/members/, urlName);

#region 内容正则表达式
StringBuilder circleReg
= new StringBuilder();
circleReg.Append(
s[0-9]\\d*.ageStr=\”(?<ageStr>.*?)\”);
circleReg.Append(
.*?s[0-9]\\d*.city=\”(?<city>.*?[^;])\”);
circleReg.Append(
.*?s[0-9]\\d*.hometownCity=(\”(?<hometownCity>.*?[^;])\”|(?<hometownCity>null)));
circleReg.Append(
.*?s[0-9]\\d*.hometownProvince=(\”(?<hometownProvince>.*?)\”|(?<hometownProvince>null)));
circleReg.Append(
.*?s[0-9]\\d*.name=(\”(?<name>.*?)\”|(?<name>null)));
circleReg.Append(
.*?s[0-9]\\d*.nickname=(\”(?<nickname>.*?)\”|(?<nickname>null)));
circleReg.Append(
.*?s[0-9]\\d*.profileImage140=\”(?<profileImage140>.*?)\”);
circleReg.Append(
.*?s[0-9]\\d*.profileImage60=\”(?<profileImage60>.*?)\”);
circleReg.Append(
.*?s[0-9]\\d*.province=\”(?<province>.*?)\”);
circleReg.Append(
.*?s[0-9]\\d*.qq=(\”(?<qq>.*?)\”|(?<qq>null)));
circleReg.Append(
.*?s[0-9]\\d*.realName=(\”(?<realName>.*?)\”|(?<realName>null)));
circleReg.Append(
.*?s[0-9]\\d*.spaceName=(\”(?<spaceName>.*?)\”|(?<spaceName>null)));
circleReg.Append(
.*?s[0-9]\\d*.userId=(?<userId>[0-9]\\d*[^;]));
circleReg.Append(
.*?s[0-9]\\d*.userName=\”(?<userName>.*?)\”);
#endregion

bool flag = true;
int i = 0;
int j = 0;
List
<CircleMemberInfo> entityList = new List<CircleMemberInfo>();
while (flag)
{
#region 构造提交参数
StringBuilder sb
= new StringBuilder();
sb.AppendFormat(
callCount=1);
sb.AppendFormat(
&page=/{0}/members/, urlName);
sb.AppendFormat(
&httpSessionId=);
sb.AppendFormat(
&scriptSessionId=D4DAC4AD9C3BF9B71C82802BDDBA0C25369);
sb.AppendFormat(
&c0-scriptName=CircleBean);
sb.AppendFormat(
&c0-methodName=getNewCircleUsers);
sb.AppendFormat(
&c0-id=0);//保留字符
sb.AppendFormat(&c0-param0=number:{0}, circleId);//11
sb.AppendFormat(&c0-param1=number:{0}, pageSize);//数量
sb.AppendFormat(&c0-param2=number:{0}, pageSize * i);//0,30,60
sb.AppendFormat(&c0-param3=boolean:true);
sb.AppendFormat(
&batchId={0}, i);

i++;

#endregion


然后我们通过代码来获取页面数据了,实现代码如下:

string content = “”;
try
{
httpHelper.ContentType
= text/plain;
content
= httpHelper.GetHtml(url, cookie, sb.ToString(), true, refUrl);
re
= new Regex(circleReg.ToString(), RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace);
mc
= re.Match(content);
}
catch (Exception ex)
{
LogTextHelper.WriteLine(ex.ToString());
break;

}


然后我们就开始用正则表达式来分析返回的数据,以便显示或者添加到数据库中,以供他用,代码实现如下所示:、

MatchCollection mcs = re.Matches(content);
foreach (Match me in mcs)
{
#region MyRegion
j
++;

sql = string.Format(@”insert into CircleMember(userId,userName,realName,nickname,circleId)
values(‘{0}’,'{1}’,'{2}’,'{3}’,'{4}’)
, me.Groups[userId].Value, httpHelper.RemoveHtml(UnicodeHelper.UnicodeToString(me.Groups[userName].Value)),
httpHelper.RemoveHtml(UnicodeHelper.UnicodeToString(me.Groups[
realName].Value.Replace(, “”))), httpHelper.RemoveHtml(UnicodeHelper.UnicodeToString(me.Groups[nickname].Value.Replace(, “”))), circleId);
command
= db.GetSqlStringCommand(sql);
try
{
db.ExecuteNonQuery(command);
}
catch (Exception ex)
{
LogTextHelper.WriteLine(sql);
LogTextHelper.WriteLine(ex.ToString());
}

message = string.Format(正在处理{0} 正在写入数据{1}次, urlName, j);
CallCtrlWithThreadSafety.SetText(
this.lblTips, message, this);
Application.DoEvents();
Thread.Sleep(
10);
#endregion

}


以上就是获取数据的一个完整的过程,其中涉及到获取圈子大类、圈子分类、圈子信息,以及最终获取圈子的用户信息,其中较为详细的介绍了各种数据的正则分析过程,如果您有这方面的应用,一个可以参考下面的代码,第二个也可以参考我的软件《易博搜搜》,其中就涉及到了网易博客圈子的邮件采集,如下所示。


该软件除了可以采集网易博客圈子用户的邮件信息,给营销推广人提供资料外,还可以利用网易博客的找朋友模块,获取相关的用户数据信息,当然也是可以转换为邮件地址信息的了,如下所示。

以上对网易博客的应用的代码实现以及一个较为综合的软件产品介绍,希望能带给大家更多的启示和知识了解。

[转载]黑客伪造Google Android更新,瞄准中国Android用户

mikel阅读(888)

[转载]黑客伪造Google Android更新,瞄准中国Android用户_IT新闻_博客园.

据安全公司赛门铁克(Symantec)报道,Google最新的Android操作系统系统更新似乎被黑客攻破了。

Google刚刚发布一个叫做“Android市场安全工具(Android Market Security Tool)” 的程序来杀死“DroidDream”Android手机病毒,赛门铁克发现的这个病毒软件也叫“Android市场安全工具”,只不过对Google的 程序进行了重新打包。赛门铁克称这个虚假安全工具会发送短信到一个指挥控制服务器。目前他们正在分析病毒代码,这个病毒是在一个第三方应用市场中发现的, 攻击对象是中国用户。

最令人震惊的是这个病毒的代码托管在Google Code 上,采用了Apache许可协议。该病毒表明黑客对Android很感兴趣。

上周Google罕见地强制用户在Android手机上安装了Android市场安全工具,以便除去DroidDream病毒。通常负责向设备 发布更新的都是手机厂商或电信运营商,Google很少自己发布更新。Google之所以这么做是因为Google官方Android应用市场中有50多 款应用感染了DroidDream病毒,该病毒可以盗取用户的IMEI、IMSI等信息,然后发送到一台位于加州Fremont的服务器上。

DroidDream还会下载其他代码到用户的手机上,利用“exploid”和“rageagainstthecage”两个漏洞来感染手 机。Google已经在Android 2.2.2以上版本中打上了补丁,但遗憾的是很多Android用户没有安装最新版Android。卡巴斯基病毒分析师称Google的这个工具并没有修 复遭到攻击的漏洞,只不过除去了DroidDream。

[转载]WordPress 主题制作技巧之一 为 previous_post_link 等链接添加 title 属性

mikel阅读(923)

[转载]WordPress 主题制作技巧之一 [ 为 previous_post_link 等链接添加 title 属性 ] – Liu is Coding – 博客园.

使用 WordPress 自己搭建博客的网友可能越来越多,我用它也有一段时间了,尽管运行效率并不让人满意,但其丰富的插件让人着迷。WordPress 虽然有着众多的免费主题,但我想还是有很多朋友还是倾向于自定义个性鲜明的主题。我打算做一个极其简易的主题,让我的 WordPress 程序像个日记本一样一页一页地翻阅。制作主题和调整程序的过程中遇到一些小问题,本着学习的态度现在把它们记下来,也希望能给遇到这些问题的人提供一点我 的意见。
今天我要说的是:为 previous_post_link 等链接添加 title 属性
previous_post_link 和 lt_next_post_link 是经常用于单文章页面 single.php 中的用来链接上一篇和下一篇文章的函数,用过这两个函数的人会发现,函数执行结果在前台输出之后,当访客的鼠标滑过时是没有任何提示的,这在有时会造成一 定的不便,为了解决这个问题,我决定给 previous_post_link 和 lt_next_post_link 加上 title 属性。
先找到 previous_post_link、lt_next_post_link 以及与其相关的 adjacent_post_link 函数的代码,其代码位于根目录下的 wp-includes/link-template.php 文件中(大约是在1300多行的样子)。当然可以从这个文件里面直接改 previous_post_link、next_post_link、 adjacent_post_link 这三个函数,但是考虑到 link-template.php 是 WordPress 的核心文件,以后不知道哪次升级时就会被替换,所以我在模板文件夹中的 functions.php 中新建了三个函数 (lt_previous_post_link、lt_next_post_link、lt_adjacent_post_link) ,新建的这三个函数在原来函数的基础上增加了 title 属性。这样我模板文件中调用新建的 lt_previous_post_link 和 lt_next_post_link 来链接上一篇和下一篇文章。

代码如下:
1. previous_post_link、lt_next_post_link、adjacent_post_link 函数的代码
2. lt_previous_post_link、lt_next_post_link、lt_adjacent_post_link 函数的代码

效果如下:
1. 在模板中调用 previous_post_link、next_post_link 的效果
2. 在模板中调用 lt_previous_post_link、lt_next_post_link 的效果

OK,完成。

[转载]外挂基础知识入门教学|工具下载

mikel阅读(1022)

[转载]外挂基础知识入门教学|工具下载 – 游戏开发:主席 – 博客园.

外挂基础知识入门教学|工具下载

{threadNotes} 外挂制作必备工具下载.

工具下载:
peid 0.94    用于查壳,知道什么壳就可以脱壳拉.
http://www.pediy.com/tools/unpack/File_analysers/peid/peid.rarOllyDbg调试器    调试游戏.
http://www.pediy.com/tools/Debuggers/ollydbg/OllyICE.rar
OD脱壳脚本    用于脱壳.
http://www.pediy.com/tools/Debuggers/ollydbg/script.htm

LordPE    一般用于脱壳.不过还有别的妙用…
http://www.pediy.com/tools/PE_tools/Lordpe/LPE-DLX.rar

ImportREC    脱壳修复工具
http://www.pediy.com/tools/PE_tools/Rebuilder/Import%20REC/ucfir16f.rar

eXeScope    资源编辑修复工具
http://www.pediy.com/tools/Resource/eXeScope/eXeScope.rar

freeRes    资源提取工具(注册码随意输入).
http://www.pediy.com/tools/Resource/freeRes/freeRes0.94.zip

Resource Hacker    资源编辑修复工具
http://www.pediy.com/tools/Resource/Resource%20Hacker/reshhack3.4.zip

WinHex    十六进制编辑工具(一般用来提取游戏的列表等…)
http://www.pediy.com/tools/Editors/winhex/WinHex_12.75_SR-6_HA.rar

UltraEdit    做外挂的~没几个不用这个^^(抠地图必须要用的哈..)
http://www.pediy.com/tools/Editors/Ultra-Edit/Ultraedit.14.hh.rar

IDA    反汇编工具(一般网络游戏加解密这个一键就可以了.)
http://www.pediy.com/tools/Disassemblers/ida/DataRescue.IDA.Pro.Advanced.v5.2.windows-YAG.zip

C32Asm    静态反汇编牛X工具
http://www.pediy.com/tools/Disassemblers/C32Asm/C32Asm.rar

Cheat Engine    目前最好用的内存修改器
http://dl-sh-ctc-1.pchome.net/3p/hl/0706_by_10_gamersky.rar

{threadNotes} Re:外挂源代码&教学&工具下载[包含商业源代码]

首先,我想说明几点:
第一,这篇文章并不是具体教你如何写外挂,只是带你大致浏览一下网游外挂的制作流程,并就其中的一些关键技术点加以简单说明。大家可以用看故事书的心情来阅读此文,了解一下网游外挂制作过程中的一些原理。
第二,网游数据的破解爱麻烦,通常一个网游外挂制作团队内都有一名破解高手坐镇。所以碰到破解方面的问题我就只能一笔带过了。一、游戏封包的加密与解密算法的破解
破解封包的加密与解密算法是制作外挂的第一步,是外挂制作中最具技术含量的步骤,同样也是一个十分令人头痛的环节。如果加密与解密算法被成功地破解,那 么外挂制作也就完成了一半。破解封包的加密与解密算法的行为同样属于黑客们其中之一的行为,因此我们可以在黑客网站里找到相应的资料,另外网络上也有专门 的破解网站为大家提供信息。
在破解封包的加密与解密算法之前我们首先需要知道一些情况。我们知道随着机器性能的提高与网络带宽的提升,新的游 戏运行商对游戏封包的加密与解密算法的设计变得越来复杂。那种原先通过分析封包数据就可以得出加密与解密算法的时代已经变成了过去。现在如果再要破解一个 游戏的封包的加密与解密算法,那么其必须通过分析程序源代码才能清楚。
1.1 封包的概念 本文所讲的封包是指由sockets协议进行发送与接收的数据包。广义的封包是指计算机之间互相进行通信的数据包,其可以因通信协议的不同而在内容上有所不同。
1.2 破解原理 目前破解封包加密与解密算法的方法主要是通过动态调试技术来实现的。其原理是首先通过动态调试跟踪并取出加密与解密算法的代码段,然后再通过分析这些代码最终得出结论。
那为什么我们可以跟踪并取得这些代码呢?首先我们知道无论游戏程序如何设计,其加密与解密算法的代码永远存在于程序中;其次我们知道在程序流的执行过程中,加密与解密算法的代码段一定会被执行。
1.3 破解需要具备的知识 要能顺利进行破解则必须具备一定的知识,一是熟练掌握汇编原理与汇编语言,二是要熟悉加壳与脱壳原理(虽然很多游戏不需要),三是要熟悉代码结构的知识,四是要熟悉动态调试技术与调试工具的使用,五是具有高级语言知识与较高的编程修为。
1.4 破解的技术与方法 动态调试工具我们可以采用OllyDbg工具或其他工具,不熟悉OllyDbg工具的可以查看它的中文帮助。动态调试主要是跟踪代码的 执行,而我们查找加密与解密代码段就是一个跟踪的过程。一般跟踪的起点可以是windows消息、socket中的send与recv等函数。有时程序有 可能将发送与接收过程由一个专门的线程进行处理,那么这种情况下我们需要找出该处理线程。至于具体如何进行跟踪本文不再进行详述,具体内容可以到相关网站 上查看,比如看雪学院、笨冬瓜等网站。这里主要讲一下加密与解密算法代码的特征。
1.5 加密与解密算法代码特征 虽然在未进行分析之前我们很难判断一段代码是否是加密或解密算法,但我们还是可以根据一些特征进行较大概率的猜测。一情况下加密 与解密都要进行一系列的异或、移位、加减、乘除和重复运算过程,因些一段代码中若具有上述特征,我们可以进行较为肯定的断定。
1.6 代码反推导 代码反推导是进行破解算法的主要方法,代码反推导的水平主要与一个人自身的编程修为相关,但在这里仍有一些基本的方法。代码反推导可以有一定 的程式,首先可以将汇编码写成三元表达码,其次将代码中的转移指令转换为条件语句或循环语句,再次将代码中的变量进行迭代,最后进行变量形式转换与语句形 式转换。通过以上的步骤,一般我们可以将汇编语言转换为高级语言,而当我们推导出高级语言后,就能进行较为实义的分析。

①.选择一款目标游戏
制作网游外挂的第一步就是选定一款游戏。目标游戏不是乱选的,里面也有很多讲究。
第一点,选择自己熟悉的游戏类型。如果你之前已经做过网游外挂,那选择一款类似的游戏会给你节省很大的时间,如果是第一次制作的话,那也选一款自己熟悉的游戏类型。
第二点,尽量不要选择热门的游戏,因为热门的游戏往往意味着竞争对手的增多,而且反外挂系统也比较厉害。像梦幻诛仙驱动+反外挂…头疼.
第三点,不要小看玩家人数少的游戏,游戏规模小,一般技术也比较容易突破。如果想销售的话。一款游戏,只要你能形成吃独食的场面,再加上营销搞得好的话,其中的利润将超过你的想象。但要注意,最好不要碰上因为游戏规模过小导致游戏厂商把游戏关闭的衰事。
第四点,尽量选择尚在测试期内的游戏,这使得你有充足的时间制作外挂。

②.目标游戏初分析
1.确定制作网游外挂的类型.
目标网游选定好之后,你首先要做的第一件事就是确定你要制作的网游外挂类型。
网游外挂虽然统称为外挂,但细分的话可以分为以下二类:内挂和脱机外挂。
内挂就是在游戏内呼出的网游外挂,它依赖于网游客户端,所使用到的技术主要包括鼠标和键盘的模拟,内存特殊变量区域的搜索,或者是挂钩游戏的收包函数和模拟游戏的发包函数。
脱机外挂就是指不依赖于客户端,能独立模拟客户端和游戏服务器进行通讯的网游外挂。脱机外挂的实现方式只有一种,就是模拟网游客户端的收包和发包过程。
总体而言,内挂的整体制作难度比脱机外挂要简单一些,但脱机外挂制作要比内挂更有趣,而且用起来也更方便,不必启动庞大的客户端程序。
某些时候脱机比较容易上手,分游戏也不是都是这样。所以以下都是脱机教学为例:

二、游戏指令与数据结构的筛查
游戏指令和指令中所携带的数据结构的筛查是外挂制作的第二步,这一步并不是很难,但十分烦锁。游戏指令和其数据结构的筛查并无技巧可言,主要是通过多次重复比较数据而最终确定结果。
在筛查游戏指令和其数据结构之前我们需要对封包截获技术有所了解,同时能对当前流行的几款封包截获工具如FPE、WPE等有所熟练使用。然而由于某些游 戏运行商会针对一些问题而制定相应对策,因此有些时候需要我们自己编写封包截获工具。自己编写封包截获工具的好处还在于可以具体针对某一款游戏而编制特定 的工具,这之中最重要的是可以事先将加密数据解密成明码,为分析封包提供方便。
2.1 封包截获技术 根据具体的截获原理不同,封包截获技术可分为:一是Hook技术、一是socket重写技术。无论使用何种截获技术我们最终要跟踪的都是socket中的发送函数与接收函数,如send、recv等。
2.1.1 Hook原理 Hook原理是通过向应用程序中注入dll文件,并改写应用程序函数导入表中的DLL调用函数,Hook技术要求我们对可执行程序的文件即PE文件结构有所了解。
2.1.2 socket重写原理 socket重写原理是通过重写整个socket文件,用新写的socket文件代替原socket文件,并由新socket文件 调用原socket文件中的函数,从而截获函数的调用过程。socket重写技术要求改写后的socket文件具有跟原socket文件相同的接口,否则 程序调用将发生错误。
2.2 封包的分析 封包分析时最重要的就是尽量减少分析时的干扰,干扰越少越有利于我们能针对性地得到结果。因此封包分析时一般是将游戏角色尽量带到一个玩家或怪物比较少的地方,同时在分析出一个后尽量过滤一个。
2.3 分析结果的处理 封包分析完毕后,我们可以为每一个指令定义一个含义比较明确的代码,并为每条指令所携带的结构信息定义相应的数据结构,为指令中的状态码也定义相应的代码。为所有指令与数据结构进行相应的定义,可以使我们在后续的外挂代码书写过程中隐藏掉实现的细节。

1.网络截包工具(Microsoft Network Monitor)的使用简介
目 标网游的初步分析最主要的工作是分析游戏初始阶段网游客户端和服务器之间的数据通讯。这一阶段主要是指从输入用户名和密码开始登录游戏到玩家人物出现在游 戏场景中这个阶段。这是开始阶段最关键的一个步骤,如果你能够成功破解网游数据通讯部分的加密,并用Debug程序成功模拟整个登录过程,那你几乎就已经 成功了一半了。如果无法破解加密的话,那就需要赶快重新选定一款游戏了。或者请高手或者朋友帮你分析=。=
关于初步分析,首先要确定网游客户端和服务器之间的大致通讯过程,最起码你要知道客户端连接的是哪一个服务器,连接的端口是多少,在登录的过程中发送和接受了几个包?而要了解这些东西,你就要使用到网络截包工具了。
初学者可以使用.Microsoft Network Monitor V3.1,方便简单。大家可以到下面的网址去下载该软件。
http://support.microsoft.com/kb/933741/zh-cn

下面,我简单介绍一下该软件的使用方法。
安装好程序之后,运行程序,点击【Start Page】页的【Create a new capture tab】按钮,创建一个新的数据捕获会话,点击工具栏上绿色的开始按钮,就可以开始捕获网络数据了。整个程序的界面如下图所示:

各个窗口的作用如下:
Network Conversations下面有二项:
My Traffic代表本机作为发送方或者接收方参与的网络数据包。选中该项后,Frame Summary中将仅仅列出与本机相关的网络数据包。
Other Traffic 则是网络上其他机器之间的网络数据包。因为正好在拦截期内经过本机,所以被顺道拦截了下来。
Capture Filter 是设定拦截数据时的过滤器。
Display Filter 是对拦截结果的过滤设定。
Select Networks 是设定需要拦截本机上的那一个网络。
Aliases用于设定友好名。
Frame Summary 中列出的是符合条件的所有网络数据包
Frame Details则是当前选中的网络数据包的详细结构
Hex Details 则是当前选中网络数据包的二进制格式

2.分析初始阶段C/S网络数据通讯
简单介绍了网络截包工具的使用之后,下面我们就开始初步分析了。
在这篇文章里,我以某款网络游戏作为假定目标。(具体是哪一款,大家就不要深究了。)
首先在【aliases】窗口中将本地客户端和游戏服务器分别命名为:MyComputer和GameServer。注意不要忘了点击【apply】按钮。

然后在【Display Filter】中输入如下语句,仅显示游戏客户端和服务器之间的数据包。数据包类型为TCP是因为网游通讯的协议是TCP协议。

下图中的数据包列表就是目标网游从输入用户名和密码登录游戏到人物出现在游戏中(然后立即退出。)这一阶段客户端和服务器之间的所有往来的数据包。

图中红线标识的三个包代表了一个连接的过程。注意它的TCP Flags的变化。
MyComputer  è  GameServer  .S…… 客户端请求建立连接
MyComputer  &ccedil;  GameServer  .S..A… 服务器同意建立连接
MyComputer  è  GameServer  ….A… 连接建立
以上三个包称为建立TCP连接的三段式握手。当你调用Socket类的Connect方法时就会产生上面的三个TCP包。

图中蓝线标识的是连接断开的过程。
MyComputer  è  GameServer  F…A… 客户端请求断开连接
MyComputer  &ccedil;  GameServer  ….A… 服务器同意断开请求
MyComputer  &ccedil;  GameServer  F…A… 服务器请求断开连接
MyComputer  è  GameServer  ….A… 客户端同意断开请求
调用Socket类的Disconnect方法时就会产生上面的四个TCP包。
从上图中我们不难看出在验证用户名和密码的过程中,客户端和服务器之间总共连接了二次,所以在之后的外挂程序编写过程中,我们同样也要连接二次。

TCP Flag为…PA…表示该TCP包内带有数据,而….A…则是回应包,用于回应上一个包的发送方:我已经收到你上一个包 了,它本身不带数据。所以一般一个…PA…包都有一个对应的….A…包(例如编号为266和269),但如果回应的时候,发现正好有数据 要发送,则可以将回应包掺杂在发送包中发送过去(例如编号为273的回应包就掺杂在275这个包内)。
下面观察客户端和服务器之间的实际数据往来。
1. 客户端连接到服务器
2. MyComputer  &ccedil;  GameServer  服务器给客户端发送7字节的数据
3. MyComputer  è  GameServer  客户端给服务器发送90字节的数据
4. MyComputer  &ccedil;  GameServer  服务器给客户端发送65字节的数据
5. MyComputer  &ccedil;  GameServer  服务器给客户端发送48字节的数据
6. MyComputer  è  GameServer  客户端给服务器发送48字节的数据
7. MyComputer  &ccedil;  GameServer  服务器给客户端发送208字节的数据
8. 服务器断开连接
9. ……
以 上就是第一次连接的大致过程。观察每个包内的具体传输数据是没有意义的,因为网游之间的通讯肯定是加密的,你每次拦截下来的数据都会不一样。通常游戏服务 器给客户端发送的第一个包都是KEY包(例如上面的7字节的包),客户端在接收到KEY包之后执行相应的数据加密初始化。所以接下来的任务就是根据已掌握 的数据通讯规律,对游戏客户端的加密算法进行破解了。

3.游戏加密算法破解
网 络游戏所使用的网络通讯函数肯定也是微软操作系统所提供的标准API函数,所以通常在接受网络数据的API函数中下一个断点,当接收到第一个7字节包时, 断点激活,然后逐渐跟进去,查看游戏客户端是如何处理该段数据的,然后我们在外挂中依样画葫芦,进行同样的处理。整个破解过程相当的枯燥无聊,因为面对的 都是汇编代码。大致的说一下。

4.Debug版本制作
破解完成之后,就要制作一个能够登录游戏的Debug版本了,用于确认游戏加密算法的破解是否成功。
至于选择何种编程语言和工具制作外挂则没有限定,常用的如VC,Delphi,等都可以易语言和VB不太推荐局限性太多~但并不是说语言不好,具体的编程在此就不具体说明了,可以根据个人的喜好所选择,
下面谈谈网游中数据通讯的基本单位:指令包。
所 谓指令包就是代表了一个最基本含义的数据包。比如游戏人物向左移动时,游戏客户端就会向服务器发送一个指令包(人物走路包),通知服务器更新游戏人物的坐 标。当游戏人物周围出现一个新的怪物时,服务器会向客户端发送一个指令包(怪物出现包),通知客户端在画面上绘制出该怪物。所以,可以说指令包就是客户端 和服务器之间所使用的通讯语言,而外挂的工作就是解析该种语言,然后模拟客户端和服务器端进行通讯。

各个游戏定义的指令包的格式都不一样,但一般一个指令包通常含有以下几个元素:
XX XX XX XX XX XX XX …
XX XX 红色部分通常与该指令包的长度相关。他可能是指整个指令包的长度,也可能是指他余下部分指令的长度,这需要根据游戏的具体情况来确定。
之所以专门要用一定空间来说明指令包的长度,这是由SOCKET通讯的机制所决定的。
SOCKET连接建立好之后,通过SOCKET连接读取到的数据并不是以指令包为分割的。有可能一个TCP包中正好包含一条指令包,也有可能仅仅包含指令包的一部分(如下图所示)。所以这时候就要根据指令包长度将收到的网络数据截取成单个的指令包。

有一点需要指出的是:刚开始的几个数据包不一定遵循一定的规律,这时候就需要进行特殊处理(因为在开头,所以也比较好处理),而之后的数据包肯定是遵循指令包格式的,不然就乱套了。

XX XX 蓝色部分通常称为指令包标识,用于说明该指令包是属于哪一种类型。比如怪物攻击包,玩家的移动包……,游戏客户端根据收到的相应指令包采取不同的动作。事实上,在客户端程序的内部就是一个很大的Switch语句,用来处理不同的指令包,如下所示:
Switch(指令包类型)
{
Case 移动包: 绘制相关人物的移动; break;
Case 攻击包: 绘制A攻击B的画面; break;

}

XX XX XX 部分是指令包详细的信息,该部分随着不同的指令包而有不同的格式。比如,如果是玩家移动包的话,他就会在此部分详细说明是哪个ID在移动,移动点是从哪儿到哪儿。

Debug成功制作完成的话,那我们就已经成功了一小半了。接下去的工作主要分为动态和静态二个方面。动态方面是根据已掌握的指令包格式,逐个分析游戏中的各个基本指令。静态方面则是从游戏客户端中解析出相应的资源。

③.网游基本指令分析
1.监控网游客户端的发送包和接受包
要分析网游指令,首先就要得到网游指令的数据样本。那么如何得到网游指令的数据样本呢?
首先想到的是使用网络截包工具,这种方式在网游发展早期的话还有一定的可行性,因为那时候网游大部分采用明文通讯,而现在的网游数据通讯肯定是加密的,所以使用网络截包工具截获到的数据毫无意义。
既然无法使用通用的工具,那我们只能把目光移向游戏客户端了,因为在游戏客户端内处理的肯定是未加密的数据。
像 之前的加密破解一样,跟踪游戏对网络数据的处理过程,分别找到游戏中对解密后的指令包的处理函数入口和游戏对要发送指令包进行加密的函数入口这二个地方, 然后修改这二处地方入口点的汇编指令,使之先调用我们编写的函数,然后再调用原始的过程。在我们自己编写的函数内部,分别记录下接收到的指令包和要发送的 指令包(如下图)。这样,网游客户端的发送包和接受包的监控就完成了。

2.分析网游指令的通用方法
能够获得网游指令样本数据之后,接下去就是实际的分析过程了。
一般而言,根据指令包所起的不同作用,可以将游戏指令包分为不同类别:

连接相关指令包 用于与游戏建立连接以及退出游戏时的指令包
玩家属性相关指令包 与玩家本身状态相关的指令包,在刚进入游戏系统时,服务器会发送过来大量的关于玩家角色基本信息的指令包。
环境相关指令包 由于告知玩家周围怪物/NPC/其他玩家状况的指令包
移动相关指令包 与走路相关的指令包
战斗相关指令包 与战斗相关的指令包
交易相关指令包 与交易相关的指令包
……

制作一款外挂,如果只要求基本功能的话,分析20,30个指令包应该就差不多了,如果要求功能比较完善的话,至多50个指令包也就差不多了。
具体分析的方法也很简单,无非是排除干扰因素,逐个击破,以及重复试验,确保分析结果正确。
下面的贴图是我对某一款游戏的28个指令包的具体分析。

三、游戏地图文件的破解与转换
地 图文件的转换也是外挂制作中的一项任务,外挂中使用的地图一般仅需要知道道路通行信息就可以,对于其他的视觉信息是没有必要的,因些我们需要对游戏中的地 图文件进行一定的转换工作。未被转换的游戏地图文件同样也是比较庞大的。由于不同的游戏运行商为了表达不同的游戏效果,因此其在地图文件上的格式也不尽相 同,我们必须分析某款游戏的具体的地图文件格式。
3.1 地图文件格式的分析 一般情况下地图文件并未被加密,但有些也可能进行了加密。地图文件格式的分析即可以直接分析地图文件数据,也可以通过跟踪游戏客户端 代码而破解出其实现过程。跟踪代码的方法同上述加密与解密算法的破解方法相似,所不同的是我们需要跟踪读写文件的函数。
3.2 外挂地图文件格式的组织 外挂地图文件格式是由外挂所需要的信息的要求决定的,在外挂中我们仅需要知道通路信息即可,因此外挂中的地图文件格式一般被组织 为R*C的格式。在R*C的每一格中记录地图在该点的通行状态,一般地我们可以定义通行状态为0阻塞状态为1。然而事实上有些外挂公司为防止其他外挂制作 者的破解,往往把地图文件进行一定的加密处理。

④.网游资源解析
游戏资源主要是指包含在网游客户端内的与游戏相关的数据资源:其中最重要的是地图资源,其他的资源包括NPC的位置坐标啊,地图传送点的坐标啊,等等。

1.地图资源解析
地图资源的解析是外挂制作中很重要的一个方面,寻路算法以及地图间的自动移动等都要依赖于地图资源。
外挂中所使用的地图资源不完全等同于游戏中使用的地图资源。游戏中使用的地图资源包含有更多的信息,而外挂所使用的地图称之为BOOL地图,它仅仅包含一项信息:指定的某一点是可移动点还是障碍点。

例如上图就是某个游戏地图所对应的BOOL地图,其中蓝色部分代表不可移动区域,白色部分代表可移动区域。(另外绿色的点是通过解析其他的资源文件获得的NPC的坐标点,红色点是传送点。)
那么如何获得游戏地图所对应的地图资源呢?通常在网游客户端的程序安装目录内会存在一个类似map或者res之类的目录。地图资源处在其中的可能性很大,而且地图资源本身的文件格式也比较明显,通常它都是以如下的格式存在的:

前面N个字节的地图头信息中肯定包含了地图的宽度信息和高度信息,设宽度和高度分别为W和H。后面的部分通常都是地图点信息。地图上的一个点通常由n个字节所构成,整个地图文件的大小由此计算而得: N + (W*H*n)。

所以判断是否是地图文件很简单,只要看一下文件的头,然后查看一下文件的大小。如果有一组文件满足上面的规律的话,那基本上可以肯定是地图资源文件了。
接 下来就是要把游戏地图转化为BOOL地图。前面提到地图文件中地图上的一个点通常有n个字节所构成,里面含有很多丰富的信息,而BOOL地图所关心的是否 是可移动点的信息通常仅需要用1位即可表示。(注意是位,1个字节有8位,所以n个字节总共有8n位)将一张游戏地图中所有点的该位信息收集起来组成的新 的地图就是BOOL地图。它标示了地图中那些区域玩家是可移动的,那些区域是不可移动的,为后面的寻路算法提供了基础数据。

原理明白了,接下去就是写一个程序解析地图资源。大致步骤如下:
1.  打开一个地图文件
2. 读入地图文件的头信息,解析出地图宽度和高度
3. 读 入地图点信息,对每一个点所代表的n字节数据执行位操作,提炼出其中某一位的信息,保存到自己的结构中。(此处我建议大家采用BMP格式的数据来保存提炼 出来的位信息,好处有三点:一是保存完之后,直接可以用图片浏览工具查看结果,不必自己再写一个绘制的程序,二是使用BMP格式保存的话,保存的数据容量 也小,三是在外挂中显示地图时可以将BMP图片直接作为背景图片贴在窗口上。)
由于之前你尚无法确定n字节中的哪一位代表了点的是否可移动属性,所以每一位你都要取一遍组成一幅地图,然后查看哪一幅和游戏地图最接近。多读几个地图文件做实验,很容易就可以确认下来的。

2.其他资源的解析
地图资源的解析是通过了解物理磁盘上地图文件的保存格式,然后自己写程序解析出来的,使用这种方法还可以解析其他很多资源信息。大家可以仔细观察游戏的安装目录,根据子目录和文件的名字可以分析出很多有用的信息。
但目前游戏厂商也越来越狡猾了,保存在磁盘上的资源文件通常进行了变形(压缩或者加密),使你无法通过简单的分析获得你所需要的信息。
一 种解决办法就是观察游戏是如何处理变型的资源文件的。因为在游戏中资源肯定是以原始形式存在的,通常都是在游戏初始化的时候,从磁盘上读入变形的资源文 件,然后将其恢复为原始状态的资源形式,我们就跟踪该段的处理过程,然后自己模仿写一段程序将变形资源恢复为原始资源形式。
另外一种方法就是直接 从游戏的内存中读取有用的资源信息。该方法的理论依据就是:资源信息在游戏中肯定是明文形态,而且是被有序组织的,也有部分游戏是加密过的,不过认真分析 一般抠取这些列表或者数据都不困难。比如,如果你想要获得所有游戏物品的信息列表,你可以随意选择一个物品名称,然后在游戏的内存中查找他的位置。所有的 物品在游戏内存中肯定是以某种链表的形式存在的,你只要找到了一个,就可以顺藤摸瓜,找到该链表的头,然后自己写一个程序,读写游戏的内存空间,将整个游 戏的物品列表全部读取出来。

四、外挂中智能AI部件的实现
游戏外挂智能AI部件的实现主要由算法与数据两部分组成,在一个具有推广意义的外挂中AI部分的设计是必不可少的。外挂AI部分的设计主要包括以下几方 面的内容:游戏脚本指令体系、自动行走算法、自动杀怪算法和综合控制算法,而在上述算法中相关配置文件的设计是相应算法设计不可缺少的组成部分。
由于智能AI部件的实现是一个比较复杂的事情,同时具体的实现过程可以因每个人理解不同而具有完全不相同的实现代码与实现的数据结构,但一般地它们还是具有一定的共性。
AI部分也是对一个人的分析能力的考验,下面先粗略得介绍一下几个算法的作用与意义,深入的探讨在具体的各个章节中进行。
4.1 游戏脚本指令体系 脚本是使外挂具有通用性的一个实现方法,也是对游戏角色进行控制的手段。脚本指令体系设计的好坏直接关系到外挂的功能与性能。
4.2 自动行走算法 完成自动行走是一个必备的功能,自动行走性能的好坏主要由算法决定。要实现自动行走首先必须找到行走的道路,然后再沿指定道路前进。寻路算法目前主要由A*算法来处理。
4.3 自动杀怪算法 自动杀怪也是一个必备的功能,自动杀怪性能好坏直接关系到升级速度的快慢。
4.4 综合控制算法 一部分由脚本完成一部分由程序处理,综合控制与性能最为相关,综合控制处理的好环直接影响升级的速度。
⑤.网游中的算法
1.寻路算法
外挂中最有名的,也最重要的一个算法就是寻路算法了。所谓寻路算法就是指给定一张地图数据,以及起始点和目标点,然后利用算法计算出一条路径来。它所依赖的数据基础是BOOL地图,这个我们在之前的讲述中已经成功获得了。下面讲一下具体的算法。
常用的寻路算法实现有二种,一种是A*算法,还有一种等高线算法。还记得在大学里面学过遍历图的二种算法吗,一种是深度优先,一种是广度优先。A*算法就对应了深度优先算法,而等高线算法则对应了广度优先算法。
A*算法是最常用的寻路算法了,不过它也有个很大的缺陷,那就是计算出来的路径通常是贴边的,所以如果你在游戏中观察用外挂控制的人物的走动的话,你会发现他通常是沿着障碍物的边走动的,走动起来显得很不自然。
A*算法和等高线算法在CSDN还有Gameres都有例子~这里就不重复了.

另外一点需要指出的是,寻路算法以及之前提到的BOOL地图的解析针对的都是2D的网游,那些纯3D的网游中的人物采用的是碰撞模型,一般3D游戏都是有高度的也就是Z坐标,它可以是正数也可以是负数。这个涉及的东西就多了去了这里就不在详说。

顺便提一下游戏中的走路。目前的2D网游中对于人物走动的处理方式主要有二种:一种是直接向服务器发送玩家要到达的目标地址,还有一种是以当前的坐标点为基点,给服务器发送相应的偏移量。
直 接发送目标地址的方式,如果网游服务器端做的不够严谨的话(没有对玩家要移动的地址和玩家当前地址之间的距离进行校验),可能会存在瞬移的BUG可供外挂 利用。(以前我就曾经碰到过一款有瞬移BUG的网游,利用外挂飞来飞去,飞得太猛了,后来就被游戏开发商给修正了。)
发送偏移量的移动方式见下图,是当前玩家所在的位置,如果玩家需要向上(即向北)移动一步的话,则向服务器发送偏移量7,如果要向斜向角(即西南方向)移动一步的话,则发送偏移量4。很明显,发送偏移量的移动方式不存在瞬移的可能性。

五、外挂配置文件的构造与设计
外挂配置文件的设计是属于外挂智能AI设计中的一部分。实现AI功能的基础一方面是算法,另一方面数据。算法的介绍集中在《游戏智能AI部件的实现》章节中讲述,这儿主要解述外挂中的配置文件的设计。
配置文件的支持直接与实现某种功能相关,支持的内容越全面那么与脚本配合后所能实现的功能越强大,并且对智能AI过程的设计起到帮助的作用。在一般游戏 外挂的配置文件中主要包括以下几部分内容,其分别为地图配置文件、过门配置文件、物品配置文件、怪物配置文件、NPC配置文件、装备配置文件、技能配置文 件和战斗配置文件。
5.1 地图配置文件 这部分内容由《游戏地图文件的破解与转换》的章节进行详细的讲解。地图配置文件的意义除了起显示作用外,其最重要的作为是提供寻路算法的数据支持。
5.2 过门配置文件 现在的游戏大部分是采取小幅地图切换的模式,图与图进行切换的点我们称之为过门。由于过门之间在数据上是不连续的,因些我们需要为些建立过门之间的联系。过门配置文件的意义主要是提供图与图之间寻路算法的数据支持。
5.3 物品配置文件 物品配置主要决定物品是否被捡取、丢弃、购买、出售、修理和物品所属种类等,物品的各类决定物品被何种NPC所处理。
5.4 怪物配置文件 怪物配置主要决定怪物是否被攻击、躲避及用什么形式攻击、多少等级间被攻击等。
5.5 NPC配置文件 NPC配置主要决定NPC在何图、何坐标、处理何类工作等。
5.6 装备配置文件 装备配置主要决定何种职业用何种装备、何等级别用何等装备等。
5.7 技能配置文件 技能配置主要决定何技能在何级别被何职业所学习与练习等。
5.8 战斗配置文件 战斗配置主要决定何级别该在何地图级别等。
外挂配置文件的具体构造形式主要由其内容所决定,同时可以考虑是否对文件进行加密处理。

2.其他算法
外挂中除了寻路算法之外,还有其他的一些算法应用,比如地图间移动算法:在已知各个地图间传送点的情况下,计算出从地图A移动到地图B所要经过的所有地图,这同样是一个经典的图论算法问题。
此外还有打怪时如何搜索最近怪物的算法,以及最有效的自动战斗的算法,这些算法要根据每款游戏的实际情况而进行相应的变动。

六、脚本解析器设计与游戏脚本指令
我们为什么要进行脚本解析器设计呢?其目的主要是解决外挂通用性的问题,我们知道有些游戏运行商时常会调整或扩增其游戏中的一些数据。如果我们把这些信 息硬编码在程序中,那么游戏运行商每修改一次数据,我们就要重新更改与编译外挂一次,这为外挂的推广使用带来了极大的不便。另外,脚本解析器也是作为智能 AI处理的一个部分,游戏行为的实现很大一部分依赖于脚本代码的书写。因此设计脚本解析器与游戏脚本指令体系是十分重要的,其中脚本指令体系更为重要。
6.1 脚本解析器的设计 脚本解析器设计是属于编译原理的范畴,大家如对编译原理有所掌握,那么设计一个脚本解析器是相当容易的。脚本解析器的设计是与脚本指令 体系相关的,离开了脚本指令体系的设计脚本解析器的设计也就免谈,因此在脚本解析器设计前我们首先需要设计好我们的脚本指令体系。
6.2 编译原理 编译原理是讲叙代码翻译的一门课程,编译原理主要涉及词法分析、语法分析、语法树构建、代码转译等方面的知识。现代的高级程序语言是属于形式语 言的,它是按一定的格式与规则进行书写,从而表达一定的行为与逻辑。而对于脚本解析器来讲所涉及的内容则较为狭窄,一般情况下脚本解析器被设计为解设执行 的程序体系,因此主要涉及词法分析与语法分析的内容。
6.2.1 词法分析 词法分析是指将我们编写的文本代码流解析为一个一个的记号,分析得到的记号以供后续语法分析使用。在词法分析中同样涉及到一错误的判断与处理。
6.2.2 语法分析 语法分析是将上述得到的记号按一定的规则进行检测,若符合某个规律则处理相应规律所对应的事情。语法分析最终可以将脚本代码的行为给解析出来,并最终完成脚本规定的行为。
6.3 脚本指令体系与组成 脚本指令体系是脚本设计中的核心,脚本指令体系设计的合理与优异与否直接与外挂能力与智能水平直接相关。一般情况下脚本支持的指令越 多则脚本所能实现的能力越大。任何外挂中使用的脚本主要具有以下几个要素:自定义变量支持语句、类型识别能力、赋值语句、脚本流控制语句、系统变量支持语 句、数值和字符串运算语句、比较语句及游戏操控语句等。
6.3.1 自定义变量支持语句 主要考虑变量的作用域与变量类型的问题。变量作用域在外挂中主要分为全局与局部两类。变量类型在外挂中主要分为数值型、字符串型和时间型三类。另外变量所能接收数据的长度也必须给予考虑。
6.3.2 类型识别能力 这类处理可以用显性或用非显性的方法进行处理,显性处理较为符合目前大多数编程语言的习惯。
6.3.3 赋值语句 分为数值型、字符串型与时间型三类数据的赋值问题。一般采用主流程序使用的方法,这种方式的用户较为广泛。
6.3.4 脚本流控制语句 分为条件语句、多分支语句、真性循环语句、假性循环语句、计数循环语句和强制跳转语句。
6.3.5 系统变量支持语句 与实际的游戏相关。比如游戏中角色的职业、级别等,另外也可以设定游戏中没有的但我们使用频繁的变量。系统变量的多少直接与脚本所能支持的功能和执行的性能有关。
6.3.6 数值和字符串运算语句 数值间有加减乘除等运算,字符串有相连定位查找等运算,时间有加减等运算。
6.3.7 比较语句 游戏中的比较语句主要包括数据间的比较、字符串的比较和时间的比较。比较方式主要有大小与相等。
6.3.8 游戏操控语句 与实际的游戏相关,比如买、卖、修、存、取、捡、丢、用、走、砍、挖、杀等,具体格式由游戏决定。
⑥.题外话
网游外挂产业真的是一个很有趣的领域,他主要是包含二个方面:技术和营销。
技 术方面,网游外挂所涉及的技术之广并不逊色于一款网游所涉及的技术。其中技术难度最大的还是破解方面,据闻中国几大顶尖的破解组织高手大部分都与外挂破解 有或多或少的联系。近几年随着大部分的游戏都运用了NProtect,在与NProtect的逐渐斗法过程中,战场从RING3层逐渐转移到系统内核层, 也着实培养出了一批对于Window内核有深刻理解的高手,国人之幸啊。
讨论网游的技术是一个很有趣的话题,但个人认为更有趣的方面在于网游外挂 的营销。由于近几年网游外挂制作团队的大量涌现。同一款游戏常常有着好几家外挂在互相竞争。这时候的外挂营销就像一个硝烟弥漫的战场,你不仅要与外挂同行 竞争,还要和游戏发行商互相斗法,同时随着近几年相关法律的健全,你还要小心自己不要被相关政府部分盯上。
在与同行竞争的过程中,不仅要比拼技术 (游戏采用了更严密的保护手段,你还要能破解它),比拼反应时间(游戏客户端有了更新,你要迅速反应),更要比拼营销手段,推出各种各样的优惠套餐,尽可 能的拉拢住更多的客户,比如,如果外挂单月的收费是20,则半年只要100,全年只要180,这样表面上你好像少收了钱,但实际上你把客户和你牢牢的绑定 住了,即使竞争对手推出更好更便宜的外挂,你也不用害怕,因为你有足够的时间来反应。类似的手段还有很多,这主要看你的营销水平了。
同时还要处理 好与竞争对手之间的关系,能很快消灭对手的,则绝不留情。明显不如对手,且对手满怀敌意的,则干脆开放免费版,让大家都不好受。势均力敌的,能结成同盟的 最好达成价格联盟,避免互相砍价给彼此造成损失。互相敌视的,则要尽量给竞争对手下绊子,比如攻击对手的站点啊,到他的论坛上面捣乱啊……,总之就是想尽 办法击败对手,取得一家独大的场面,一旦你能在一款游戏里面吃独食,形成垄断,那外挂的价格就随你定了。够你爽的。
外挂的营销就像一个群雄并起的战国时代,大家各施手段,各凭本事,看谁能笑到最后。这里面发生过很多有趣的故事。不过近几年国内相关法律越来越严格了,所以并不建议大家踏入这个泥水潭。

[转载]T-SQL之公用表表达式(CTE)

mikel阅读(923)

[转载]T-SQL之公用表表达式(CTE) – 我的成长点滴 – 博客园.

以前也写过几篇,后来总算觉得写得不够好,写了点又删了点,最后一直没有东西留下来,随着时间的流逝,几乎没有积累。最近在看T-SQL相关的 书,结合工作中遇到的问题,我打算写点东西来记录我的学习经历,希望大家指出我的不对的地方,希望一起探讨开发中的问题。小弟再次谢过了。
“T-SQL相关的”
废话就不多说了,公用表表达式(Common Table Expressions), 是SQL SERVER支持的一种类型的表表达式。
CTE的语法如下:
WITH
<cte_name> [(<target_col_list>)]
AS
(
  <定义CTE的内部查询>
)
<对CTE进行外部查询>;
CTE的语法,从WITH开始,首先在括号里定义CTE内部查询,然后在外部查询引用CTE的名称。
对CTE的内部查询表达式,有如下规则:
  1.查询必须是一个有效的表;
  2.所有的列必须要有名称;
  3.所有的列名必须唯一;
4.不允许使用order by(除非同时指定了top,原因很简单,因为order by之后,返回的是游标,但是如果同时指定了top,则order by可以当作是top的排序方式)。
下面是一个CTE的例子。
use Northwind; go with EmployeeYearOrder as ( select (e.FirstName+N' '+e.LastName) as employeename,year(o.orderdate) as theyear,COUNT(o.OrderID) ordernum from dbo.Orders o inner join dbo.Employees e on o.EmployeeID = e.EmployeeID group by e.FirstName+N' '+e.LastName,year(o.orderdate) ) select * from EmployeeYearOrder cur left join EmployeeYearOrder pre on cur.theyear = pre.theyear+1

上边的例子是多引用的CTE,利用CTE定义了每年的雇员的订单的数目,在外部查询中,通过两次引用EmployeeYearOrder ,一个代表当前年份,一个代表上一年。

如果使用派生表的话,代码是如下组织的:

use Northwind; go select * from ( select (e.FirstName+N' '+e.LastName) as employeename,year(o.orderdate) as theyear,COUNT(o.OrderID) ordernum from dbo.Orders o inner join dbo.Employees e on o.EmployeeID = e.EmployeeID group by e.FirstName+N' '+e.LastName,year(o.orderdate) )as cur left join ( select (e.FirstName+N' '+e.LastName) as employeename,year(o.orderdate) as theyear,COUNT(o.OrderID) ordernum from dbo.Orders o inner join dbo.Employees e on o.EmployeeID = e.EmployeeID group by e.FirstName+N' '+e.LastName,year(o.orderdate) ) as pre on cur.theyear = pre.theyear+1;

注意上边的查询,核心查询的部分重复了两次。查询越复杂,引用次数越多,基于CTE的解决方案越有优势。当然从性能上来讲,这两种写法,经过查询优化器分析后,最终都得到同样的执行计划。

还有多CTE的情况。CTE不允许直接嵌套,但是可以用同一个WITH定义多个CTE,从而得到和嵌套派生表相同的效果,但是却没有嵌套派生表那么复杂。

看下边的查询:

多CTE的解决方案,返回的是每个雇员每一年处理的订单的数目
with c1 as ( select YEAR(orderdate) as theyear,(e.FirstName+N' '+e.LastName) as employeename,OrderID from dbo.Orders as o inner join dbo.Employees e on o.EmployeeID = e.EmployeeID ), c2 as ( select theyear,employeename,COUNT(OrderID) ordernum from c1 group by theyear,employeename ) select employeename,theyear,ordernum from c2;

就是一个多CTE的例子,看起来比多层嵌套的派生表要直观。

CTE最大的用处,我觉得还是递归查询。

还是给出一个例子。

WITH Emps AS ( SELECT empid, mgrid, firstname, lastname FROM HR.Employees WHERE empid = 5 UNION ALL SELECT Emp.empid, Emp.mgrid, Emp.firstname, Emp.lastname FROM Emps AS Mgr JOIN HR.Employees AS Emp ON Emp.mgrid = Mgr.empid ) SELECT * FROM Emps;

这段查询将返回每位经理的直接下属。

如上查询所示,递归的CTE,必须包含至少两个查询。第一个查询被成为定位点成员, 它只是一个返回有效表的查询,作为递归的基础或定位点。而第二个查询则成为递归成员,是该查询成为递归成员的是对CTE名称的递归引用。如果担心循环的发 生,则可以指定option(maxrecursion n)来限制递归成员的调用次数。关于CTE的更多应用和深入理解,有机会再深入去讲解。

对于T-SQL公用表表达式,就讲到这里,有什么问题,还请大家指出,一起探讨。

参考文献:《Microsoft SQL Server 2008 技术内幕:T-SQL查询》

[转载]T-SQL逻辑处理之表运算符

mikel阅读(1003)

[转载]T-SQL逻辑处理之表运算符 – 我的成长点滴 – 博客园.

在前两篇T-SQL查询处理详解, T-SQL查询处理详解 (续)中,我较为详细地介绍了在一般查询中忽略实际的优化执行计划的情况下的逻辑处理过程。接下来,我将从表运算符,连接查询,分析函数,子查询等方面入手,深入地探讨这些细节,欢迎大家一起讨论T-SQL开发中遇到的问题。废话不多说,开始了。
SQL SERVER 2008支持4种表运算符,JOIN,PIVOT,UNPIOVT,APPLY,。这四种运算符,JOIN大家肯定不陌生,但是后面的几个,估计就有不少人很少使用了。
一.PIVOT。
首先看这样的一条SQL查询。

SELECT EmployeeID,
SUM(CASE WHEN theyear = 2006 THEN themoney END) AS [2006],
SUM(CASE WHEN theyear = 2007 THEN themoney END) AS [2007],
SUM(CASE WHEN theyear = 2008 THEN themoney END) AS [2008],
SUM(CASE WHEN theyear = 2009 THEN themoney END) AS [2009],
SUM(CASE WHEN theyear = 2010 THEN themoney END) AS [2010],
SUM(CASE WHEN theyear = 2011 THEN themoney END) AS [2011]
FROM (SELECT EmployeeID, YEAR(Orderdate) AS theyear, themoney
FROM dbo.Order) AS O
GROUP BY EmployeeID;
这种行转列的需求,在实际情况中特别常见,尤其是在提取年度或者月度 报表的数据时,基本少不了这种结果集。看看上面的这条查询,是不是觉得不是很好。不好在哪里呢?有两点,1.代码量大,而且重复代码太多,碰到很多行要转 成列的情况,就非常麻烦了。在项目里,经常碰到做月度报表,需要把12个月的数据利用这种写法转成列,就让人吐血了;2.执行效率不高。
这时,我向您介绍T-SQL中特有的表运算符,PIVOT。Pivot运算符用于在列和行之间对数据进行旋转或透视转换,同时执行聚合运算。对于上面的需求,用PIVOT可以如下实现相同的功能:
SELECT * FROM (SELECT EmployeeID, YEAR(Orderdate) AS theyear, themoney
FROM dbo.Order) AS O
PIVOT(
SUM(themoney) FOR theyear IN([2006],[2007],[2008],[2009],[2010],[2011])) AS P;
怎么样,是不是简洁多了?
来简要分析一下PIVOT的执行过程。PIVOT运算符用一个名为O的表表达式作为它的左输入,每个订单占一行,包含EmployeeID和theyear和themoney。
PIVOT操作涉及到一下三个逻辑阶段。
1.分组。来看看PIVOT子句,我们发现,PIVOT运算符引用了表O(给表取的别名)的两个列作为输入参数,分别是themoney和 theyear。在这个阶段,会隐式对表O中的行进行分组,分组依据是根据那些没有作为pivot输入参数的所有列。所以,就相当于有一个隐藏的 group by EmployeeID一样,最后结果集就是每个EmployeeID作为一个组。
2.扩展。这个阶段是把原始列的值扩展到他们相应的目标列中,在逻辑上,相当于为IN子句中指定的每个目标列使用以下case表达式:
CASE WHEN <spreading_col> = <target_col_element> THEN <expression> END.
注意一点,不带ELSE的CASE子句相当于包含了一个隐式的ELSE NULL。
3.聚合。这个阶段就是对每个CASE表达式应用指定的聚合函数,对于上边的查询,就是SUM(),并生成结果列。
对于PIVOT的更多的应用,有机会再深入了解。
二.UNPIVOT。
很明显,UN这个前缀表明了,它做的操作是跟PIVOT相反的,即列转行。UNPIVOT操作涉及到以下三个逻辑处理阶段。
1,生成副本
2,提取元素
3,删除带有NULL的行
看看这个MSDN上的例子。

CREATE TABLE pvt (VendorID int, Emp1 int, Emp2 int,
Emp3
int, Emp4 int, Emp5 int);
GO
INSERT INTO pvt VALUES (1,4,3,5,4,4);
INSERT INTO pvt VALUES (2,4,1,5,5,5);
INSERT INTO pvt VALUES (3,4,3,5,4,4);
INSERT INTO pvt VALUES (4,4,2,5,5,4);
INSERT INTO pvt VALUES (5,5,1,5,5,5);
GO
Unpivot the table.
SELECT VendorID, Employee, Orders
FROM
(
SELECT VendorID, Emp1, Emp2, Emp3, Emp4, Emp5
FROM pvt) p
UNPIVOT
(Orders
FOR Employee IN
(Emp1, Emp2, Emp3, Emp4, Emp5)
)
AS unpvt;
GO
简单对上边的查询作一个分析。UNPIVOT的输入是左表表达式P,第一步,先为P中的行生成多个副本,在UNPIVOT中出现的每一列,都会 生成一个副本。因为这里的IN子句有5个列名称,所以要为每个来源行生成5个副本。结果得到的虚拟表中将新增一个列,用来以字符串格式保存来源列的名称 (for和IN之间的,上面例子是Employee )。第二步,根据新增的那一列中的值从来源列中提取出与列名对应的行。第三步,删除掉结果列值为null的行,完成这个查询。
三.APPLY。
APPLY运算符是把右表表达式应用与左输入中的每一行。对于左表中的每一行,都要计算一次右边输入的表达式。
APPLY 有两种形式:CROSS APPLY 和 OUTER APPLY。CROSS APPLY 仅返回外部表中通过右表表达式生成结果集的行。OUTER
APPLY 既返回生成结果集的行,也返回不生成结果集的行,其中右表表达式生成的列中的值为 NULL。(外部表:左边表,内部表:右表表达式)

以下示例查询为每个客户返回具有最大订单ID的两个订单:
SELECT C.customerid, C.city, A.orderid
FROM dbo.Customers AS C
CROSS APPLY
(SELECT TOP (2) O.orderid, O.customerid
FROM dbo.Orders AS O
WHERE O.customerid = C.customerid
ORDER BY orderid DESC) AS A;
如果将CROSS APPLY换成了OUTER APPLY,则会把不满足右表表达式的行添加进来,并给内部表的列设为NULL。
欢迎大家一起探讨T-SQL开发,并提出问题,一起讨论。
参考文献:《Microsoft SQL Server 2008 技术内幕:T-SQL查询》

[转载]分享45个海量免费电子书下载网站

mikel阅读(1169)

[转载]分享45个海量免费电子书下载网站 – 梦想天空 – 博客园.

随着网络和信息技术的快速发展,电子书越来越流行。以Amazon Kindle为代表的电子书阅读器的出现改变了人们传统的阅读方式,如同iPod改变人们听音乐一样。如今,很多网上书店也推出了电子书商品,相比传统的 纸质书,电子书便携、容易使用、大容量的特点非常适合现代生活,用户可以以更低的价格方便的购买到更多的图书,为电子书的流行奠定了基础。今天要与大家分 享的是45个非常有用的免费电子书下载网站,还等什么呢,赶紧淘书去吧:)

Ebooklink.net

ebooklink.net

一个免费电子书搜索引擎,超过200,000本电子图书供下载,有计算机,经济,健康,小说等各种类别。

SearchPDFebooks
SearchPDFebooks

一个海量免费电子书搜索引擎,超过255,000,000免费PDF格式电子书供下载

Scribd
image
一个非常流行的在线文件共享社区,您可以在线阅读电子书和下载PDF、TXT或DOC格式的电子书。

University of Virginia library

image

最好的在线图书馆之一,可通过搜索查找电子书。

Diesel eBooks
Diesel ebooks
提供了供Microsoft Reader和Mobipocket Reader阅读的免费电子书,有计算机类的电子书。

PDFgeni
PDFgeni
一个免费的PDF搜索引擎,输入书名或者你要查找的书的关键词。

Globusz
clip_image020
可以在线免费阅读图书,你也可以下载你喜欢的电子书。

Free-ebooks
Free-ebooks
可以下载小说,健康,计算机和互联网等很多完全免费的电子书。

Freebookspot
Freebookspot
汇集从互联网上收集的免费电子书链接。

Getfreeebooks

Getfreeebooks

一个免费的高质量电子书下载网站,你也可以分享您的电子书给Getfreeebooks供其它人下载。

Gotenberg

image

一个优质的电子图书网站,提供可在iPad、Kindle、Android、iPhone和iPod上阅读的电子书下载。

Ebookpdf
clip_image022
超过100,000本电子图书供免费下载。

KnowFree

image

KnowFree是一个电子书门户网站,用户可以相互交换免费电子书,视频教程或者其他资料。

Onlinecomputerbooks
clip_image027

可以找到计算机和互联网,设计,编程等很多主题的图书。

Freecomputerbooks
clip_image018
免费下载电脑,编程,工程,数学,讲义和教程等类别的电子书。
EBook3000
EBook3000
一个超大的免费电子图书下载网站,有商业,技术,规划,设计等很多类别。

Freetechbooks
clip_image019

免费在线计算机科学与编程电子书籍。

EBooksLab
EBooksLab
主要以计算机和医疗方面的电子书为主。
Ebookdirectory
clip_image024
超过20,000本电子书供免费下载,一个对计算机和互联网从业人员非常有用的网站。

Witguides

image

一个分类电子书下载库,列出了下载数最多的前十本电子书。

4eBooks

image

4eBooks有非常多的计算机编程方面的电子书,每个供下载的电子书都有一个简短描述。

Freebookcentre
Freebookcentre
免费下载技术类图书,其中包括计算机科学,编程,移动技术,物理学,医学等类别的电子图书。EBooksread
EBooksread
一个免费的在线图书馆,在那里你可以阅读和下载电子图书。

Readeasily

Readeasily

提供在线阅读的网上图书馆。

Downloadfreepdf
Downloadfreepdf
下载免费的PDF格式电子图书,并下载用于在Pocket PC和Palm设备访问的电子图书。
Acrobatplanet
Acrobatplanet
一个收集各种类别免费PDF电子书的网站。

Ebooksdownloadfree
可以免费下载医疗,搜索引擎优化,小说和电脑类免费电子图书,还有一个流行电子图书排行。

PDf-search-engine

image

一个在线查找PDF格式电子书的网站。

Ebook Delicate

image

提供了用户可以自由分享他们的电子书的免费平台,这个网站没有实际的文件存储。

Zillr
clip_image025
免费电子图书门户。
Memoware
clip_image026
电子图书和掌上电脑阅读的文件。

Upenn.edu
clip_image031

超过35000本电子图书供免费下载。

Ebooksdownloadfree
Ebooksdownloadfree
可以免费下载医疗,搜索引擎优化,小说和电脑类免费电子图书,还有一个流行电子图书排行。
Ebookshare
Ebookshare
另一个免费下载电子书的网站。
PlanetPDF
PlanetPDF
一个PDF用户社区,在那里你可以找到像PDF转换工具,PDF编辑器来在线编辑你的PDF文件, 同时可下载流行的电子书。
Ebooksdirectory
E-booksdirectory
拥有大约2800本免费电子书,覆盖了400多个类别。
Onlinefreeebooks
clip_image023
一个简单的电子图书网站,提供免费电子书下载。
Manybooks
Manybooks
ManyBooks为您的掌上电脑,iPod或电子书阅读器提供免费电子书

Fictionwise
clip_image033
供Palm,掌上电脑,和Mac等平台的免费电子书。

E-books
clip_image034
免费下载PDF、CHM格式图书。

BesteBooksWorld

image

涉及题材非常广泛的电子图书网站。
Ufindbook
clip_image035
免费下载电子图书。
Snipfiles
clip_image028
提供免费电子书和软件。
Bookyards
clip_image029

一个在线图书馆,提供免费下载。
Asksam
clip_image030
免费下载电子图书和免费检索的数据库。
Ebooklobby
clip_image032
艺术,商业,电脑,烹饪,法律,体育,旅游等各种类别的免费电子图书,同时列出了最受欢迎的十大电子书。

(编译来源:梦想天空 原文来自:45+ Free Ebook Download Web Sites of Information Overload