[转载]谈谈你最熟悉的System.DateTime

mikel阅读(1066)

[转载]谈谈你最熟悉的System.DateTime – Artech – 博客园.

最近一直在负责公司内部框架的升级工作,今天对一个小问题进行了重新思考——时间的处理。具体来说,是如何有效地进行时间的处理以提供对跨时区的支 持。对于一个分布式的应用来说,倘若客户端和服务端部署与不同的地区,在对时间进行处理的时候,就需要考虑时区的问题。以我们现在的一个项目为例,这是一 个为澳大利亚某机构开发的一个基于Smart Client应用(Windows Form客户端),服务器部署与墨尔本,应用的最终用户可能需要跨越不同的州。澳洲地广人稀,不同的州也有可能会跨越不同的时区。假设数据库并不支持对时 区的区分,服务端需要对针对客户端所在的时区对时间进行相应的处理。不过,对该问题解决方案的介绍我会放在后续的文章中,在这里我们先来介绍一些基础性的 内容——谈谈我们熟悉的System.DateTime类型。

一、你是否知道System.DateTimeKind?

System.DateTime类型,我们再熟悉不过。顺便说一下,这个类型不是class,而是一个struct,换言之它是值类型,而不是引用类型。DateTime处理包含我们熟悉的年、月、日、时、分、秒和毫秒等基本属性之外,还具有一个重要的表示时间类型(Kind)的属性:Kind。该属性的类型为System.DateTimeKind枚举。DateTimeKind定义如下,它具有三个枚举值:Unspecified、Utc和Local。后两个分别表示UTC(格林威治时间)和本地时间。Unspecified顾名思义,就是尚未指定具体类型,这是默认值。

   1: [Serializable, ComVisible(true)]

   2: public enum DateTimeKind

   3: {

   4:     Unspecified,

   5:     Utc,

   6:     Local

   7: }

在DateTime类型中,表示时间类型的Kind属性是只读的,只能在构造函数中指定。相关构造函数和Kind属性的定义如下面的代码片断所示:

   1: [Serializable]

   2: public struct DateTime

   3: {

   4:     //Others...

   5:     public DateTimeKind Kind { get; }

   6:

   7:     public DateTime(int year, int month, int day, int hour, int minute, int second, DateTimeKind kind);

   8:     public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, DateTimeKind kind);

   9:     public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar, DateTimeKind kind);

  10: }

虽然,Kind属性是只读的,但是我们还用另外一中设定Kind的方式,那就是调用DateTime的静态方法的SpecifyKind。该方法不会真正去修改一个现有DateTime对象的Kind属性,而是会重新创建一个新的DateTime对象。方法返回的对象具有和指定时间相同的基本属性(年、月、日、时、分、秒和毫秒),该DateTime对象具有你指定的DateTimeKind值。

   1: public struct DateTime

   2: {

   3:     //Others...

   4:     public static DateTime SpecifyKind(DateTime value, DateTimeKind kind);

   5: }

二、几个常用DateTime对象的DateTimeKind

处理直接通过构造函数构建DateTime对象之外,我们还经常用到DateTime的几个静态只读属性去获取一些特殊的时间,比如Now、UtcNow、MinValue和MaxValue等,那么这些DateTime对象的DateTimeKind又是什么呢?

  • 当我们通过构造函数创建一个DateTime对象的时候,Kind默认为DateTimeKind.Unspecified
  • DateTime.Now表示当前系统时间,Kind属性值为DateTimeKind.Local,所以DateTime.Now应该是DateTime.LocalNow;
  • 而DateTime.UtcNow返回以UTC表示的当前时间,毫无疑问,Kind属性自然是DateTimeKind.Utc;
  • DateTime.MinValue和DateTime.MaxValue表示的DateTime所能表示的最大范围,它们的Kind属性为DateTimeKind.Unspecified。

上面列表对几个常用DateTime对象Kind属性的描述可以通过下面的程序来证实:

   1: DateTime endOfTheWorld = new DateTime(2012, 12, 21);

   2: Console.WriteLine("endOfTheWorld.Kind = {0}", endOfTheWorld.Kind);

   3: Console.WriteLine("DateTime.SpecifyKind(endOfTheWorld, DateTimeKind.Utc).Kind = {0}",

   4:     DateTime.SpecifyKind(endOfTheWorld, DateTimeKind.Utc).Kind);

   5: Console.WriteLine("endOfTheWorld.Kind = {0}", endOfTheWorld.Kind);

   6: Console.WriteLine("DateTime.Now.Kind = {0}", DateTime.Now.Kind);

   7: Console.WriteLine("DateTime.UtcNow.Kind = {0}", DateTime.UtcNow.Kind);

   8: Console.WriteLine("DateTime.MinValue.Kind = {0}", DateTime.MinValue.Kind);

   9: Console.WriteLine("DateTime.MaxValue.Kind = {0}", DateTime.MaxValue.Kind);

输出结果:

   1: endOfTheWorld.Kind = Unspecified

   2: DateTime.SpecifyKind(endOfTheWorld, Dat

   3: endOfTheWorld.Kind = Unspecified

   4: DateTime.Now.Kind = Local

   5: DateTime.UtcNow.Kind = Utc

   6: DateTime.MinValue.Kind = Unspecified

   7: DateTime.MaxValue.Kind = Unspecified

三、DateTime的对等性问题

接下来,我们来谈谈另外一个比较有意思的问题——两个DateTime对象对等性。在这之前,我首先提出这样一个问题:“如果两个DateTime对象相等,是否意味着它们表示同一个时间点?”我想有人会认为是。但是答案是“不一定”,我们可以举一个反例。在下面的程序中,我创建了三个DateTime对象,年、月、日、时、分、秒均是相同的,但Kind分分别指定为DateTimeKind.LocalDateTimeKind.Unspecified和DateTimeKind.Utc

   1: DateTime endOfTheWorld1 = new DateTime(2012, 12, 21, 0, 0, 0, DateTimeKind.Local);

   2: DateTime endOfTheWorld2 = new DateTime(2012, 12, 21, 0, 0, 0, DateTimeKind.Unspecified);

   3: DateTime endOfTheWorld3 = new DateTime(2012, 12, 21, 0, 0, 0, DateTimeKind.Utc);

   4:

   5: Console.WriteLine("endOfTheWorld1 == endOfTheWorld2 = {0}", endOfTheWorld1 == endOfTheWorld2);

   6: Console.WriteLine("endOfTheWorld2 == endOfTheWorld3 = {0}", endOfTheWorld2 == endOfTheWorld3);

由于我们处于东8区,基于DateTimeKind.Local的endOfTheWorld1和基于DateTimeKind.Utc的 endOfTheWorld3,不可能表示的是同一个时刻。但是从下面的输出结果来看,它们却是“相等的”,不但如此,Kind为Unspecified 的endOfTheWorld2也和这两个时间对象相等。

   1: endOfTheWorld1 == endOfTheWorld2 = True

   2: endOfTheWorld2 == endOfTheWorld3 = True

由此可见,DateTimeKind对等性判断和DateTimeKind无关,那么在内部是如何进行判断的呢?要回答这个问题,这就要谈谈DateTime另外一个重要的属性——Ticks了。该属性定义如下,是DateTime的只读属性,类型为长整型,表示该DateTime对象通过日期和时间体现出来的计时周期数。每个计时周期表示一百纳秒,即一千万分之一秒。1 毫秒内有 10,000 个计时周期。此属性的值表示自公元元年( 0001 年) 1 月 1 日午夜 12:00:00(表示 DateTime.MinValue)以来经过的以100 纳秒为间隔的间隔数。

   1: public struct DateTime

   2: {

   3:     //Others...

   4:     public long Ticks { get; }

   5: }

注意,这里的基准时间0001 年 1 月 1 日午夜 12:00:00,并没有说是一定是UTC时间,所以Ticks和DateTimeKind无关,这里通过下面的实例看出来:

   1: DateTime endOfTheWorld1 = new DateTime(2012, 12, 21, 0, 0, 0, DateTimeKind.Local);

   2: DateTime endOfTheWorld2 = new DateTime(2012, 12, 21, 0, 0, 0, DateTimeKind.Unspecified);

   3: DateTime endOfTheWorld3 = new DateTime(2012, 12, 21, 0, 0, 0, DateTimeKind.Utc);

   4:

   5: Console.WriteLine("endOfTheWorld1.Ticks = {0}", endOfTheWorld1.Ticks);

   6: Console.WriteLine("endOfTheWorld2.Ticks = {0}", endOfTheWorld2.Ticks);

   7: Console.WriteLine("endOfTheWorld3.Ticks = {0}", endOfTheWorld3.Ticks);

从下面的输出结果我们不难看出,上面创建的具有不同DateTimeKind的三个DateTime的Ticks属性的值都是相等的。实际上,DateTime的对等性判断就是通过Ticks的大小来判断的

   1: endOfTheWorld1.Ticks = 634917312000000000

   2: endOfTheWorld2.Ticks = 634917312000000000

   3: endOfTheWorld3.Ticks = 634917312000000000

我们经常说的UTC时间和本地时间之间的相互转化,实际上指的就是将一个具有某种DateTimeKinde的DateTime对象转化成具有另外一种DateTimeKind的DateTime对象,并且确保两个DateTime对象对象表示相同的时间点。关于时间转换的实现,我们有很多不同的选择。

四、通过DateTime类型的ToLocalTime和ToUniversalTime方法实现UTC和Local的转换

对基于三种不同DateTimeKind的DateTime对象之间的转化,最方便的就是直接采用DateTime类型的两个对应的方法:ToLocalTimeToUniversalTime,这两个方法的定义如下。

   1: public struct DateTime

   2: {

   3:     //Others...

   4:     public DateTime ToLocalTime();

   5:     public DateTime ToUniversalTime();

   6: }

实际上我们所说的不同DateTimeKind之间的DateTime之间的转化主要包括两个方面:将一个 DateTimeKind.Local(或者DateTimeKind.Unspecified)时间转换成DateTimeKind.Utc时间,或者 将DateTimeKind.Utc(或者DateTimeKind.Unspecifed时间)转换成DateTimeKind.Local时间。为了 深刻地理解两种不同转换采用的转化规则,我写了如下一段程序:

   1: DateTime endOfTheWorld1 = new DateTime(2012, 12, 21, 0, 0, 0, DateTimeKind.Local);

   2: DateTime endOfTheWorld2 = new DateTime(2012, 12, 21, 0, 0, 0, DateTimeKind.Unspecified);

   3: DateTime endOfTheWorld3 = new DateTime(2012, 12, 21, 0, 0, 0, DateTimeKind.Utc);

   4:

   5: Console.WriteLine("endOfTheWorld1.ToLocalTime() = {0}",endOfTheWorld1.ToLocalTime());

   6: Console.WriteLine("endOfTheWorld2.ToLocalTime() = {0}", endOfTheWorld2.ToLocalTime());

   7: Console.WriteLine("endOfTheWorld3.ToLocalTime() = {0}\n", endOfTheWorld3.ToLocalTime());

   8:

   9: Console.WriteLine("endOfTheWorld1.ToUniversalTime() = {0}", endOfTheWorld1.ToUniversalTime());

  10: Console.WriteLine("endOfTheWorld2.ToUniversalTime() = {0}", endOfTheWorld2.ToUniversalTime());

  11: Console.WriteLine("endOfTheWorld3.ToUniversalTime() = {0}", endOfTheWorld3.ToUniversalTime());

对于DataTimeKind为Utc和Local之间的转化,没有什么可以说得,就是一个基于时差的换算而已。大家容易忽视的是DataTimeKind.Unspecifed时间分别向其他两种DateTimeKind时间的转换问题。从下面的输出我们可以看出,当DateTimeKind.Unspecifed时间向DateTimeKind.Local转换的时候,实际上是当成DateTimeKind.Utc时间而向DateTimeKind.Utc转换的时候,则当成是DateTimeKind.Local。 顺便补充一下:不论被转换的时间属于怎么的DateTimeKind,调用ToLocalTime和ToUniversalTime方法的返回的时间的 Kind属性总是DateTimeKind.Local和DateTimeKind.Utc,两者之间的转换并不只是年月日和时分秒的改变。

   1: endOfTheWorld1.ToLocalTime() = 12/21/2012 12:00:00 AM

   2: endOfTheWorld2.ToLocalTime() = 12/21/2012 8:00:00 AM

   3: endOfTheWorld3.ToLocalTime() = 12/21/2012 8:00:00 AM

   4:

   5: endOfTheWorld1.ToUniversalTime() = 12/21/2012 4:00:00 PM

   6: endOfTheWorld2.ToUniversalTime() = 12/21/2012 4:00:00 PM

   7: endOfTheWorld3.ToUniversalTime() = 12/21/2012 12:00:00 AM

五、通过TimeZoneInfo实现Utc和Local的转换

上面提供的方式虽然简单,但是功能上确有局限,因为转换的过程是基于本机当前的时区。这解决不了我在开篇介绍的应用场景:服务端根据访问者所在的时区(而不是本机的时区)进行时间的转换。换句话说,我们需要能够基于任意时区的时间转换方式,这就可以通过System.TimeZoneInfo

TimeZoneInfo实际上对原来System.TimeZone类型的一个改进。它是一个可序列化的类型(这一点在分布式场景中进行基于时区的时间处理实现非常重要),表示具体某个时区的信息。它提供了一系列静态方法供我们对某个DateTime对象进行基于指定TimeZoneInfo的时间转换, 在这我们介绍我们常用的2个:ConvertTimeFromUtc和ConvertTimeToUtc。前者将一个DateTimeKind.Utc或 者Unspecified的DateTime时间转换成基于指定时区的DateTimeKind.Local时间;后者则将一个基于指定时区的 DateTimeKind.Local或者DateTimeKind.Unspecified时间象转化成一DateTimeKind.Utc时间。此 外,TimeZoneInfo还提供了两个静态属性Local和Utc表示本地时区和格林威治时区。

   1: [Serializable]

   2: public sealed class TimeZoneInfo : IEquatable<TimeZoneInfo>, ISerializable, IDeserializationCallback

   3: {

   4:     //Others...

   5:     public static DateTime ConvertTimeFromUtc(DateTime dateTime, TimeZoneInfo destinationTimeZone);

   6:     public static DateTime ConvertTimeToUtc(DateTime dateTime, TimeZoneInfo sourceTimeZone);

   7:

   8:     public static TimeZoneInfo Local { get; }

   9:     public static TimeZoneInfo Utc { get; }

  10: }

我们照例来做个试验。还是刚才创建的三个DateTime对象,现在我们分别调用ConvertTimeFromUtc将 DateTimeKind.Utc或者DateTimeKind.Unspecified时间转换成DateTimeKind.Local时间;然后将调 用ConvertTimeToUtc将DateTimeKind.Local或者DateTimeKind.Unspecified时间转换成 DateTimeKind.Utc时间。

   1: DateTime endOfTheWorld1 = new DateTime(2012, 12, 21, 0, 0, 0, DateTimeKind.Local);

   2: DateTime endOfTheWorld2 = new DateTime(2012, 12, 21, 0, 0, 0, DateTimeKind.Unspecified);

   3: DateTime endOfTheWorld3 = new DateTime(2012, 12, 21, 0, 0, 0, DateTimeKind.Utc);

   4:

   5: Console.WriteLine("TimeZoneInfo.ConvertTimeFromUtc(endOfTheWorld2,TimeZoneInfo.Local) = {0}",

   6:     TimeZoneInfo.ConvertTimeFromUtc(endOfTheWorld2, TimeZoneInfo.Local));

   7: Console.WriteLine("TimeZoneInfo.ConvertTimeFromUtc(endOfTheWorld3,TimeZoneInfo.Local) = {0}\n",

   8:    TimeZoneInfo.ConvertTimeFromUtc(endOfTheWorld3, TimeZoneInfo.Local));

   9:

  10: Console.WriteLine("TimeZoneInfo.ConvertTimeToUtc(endOfTheWorld1,TimeZoneInfo.Local) = {0}",

  11:     TimeZoneInfo.ConvertTimeToUtc(endOfTheWorld1, TimeZoneInfo.Local));

  12: Console.WriteLine("TimeZoneInfo.ConvertTimeToUtc(endOfTheWorld2,TimeZoneInfo.Local) = {0}",

  13:    TimeZoneInfo.ConvertTimeToUtc(endOfTheWorld2, TimeZoneInfo.Local));

同上面进行的转换方式一样,在向DateTimeKind.Utc时间进行转换的时候,DateTimeKind.Unspecifed时间被当成 DateTimeKind.Local;而在向DateTimeKind.Local时间转换的时候,DateTimeKind.Unspecifed则 被当成DateTimeKind.Utc时间。

   1: TimeZoneInfo.ConvertTimeFromUtc(endOfTheWorld2,TimeZoneInfo.Local) = 12/22/2012 8:00:00 AM

   2: TimeZoneInfo.ConvertTimeFromUtc(endOfTheWorld3,TimeZoneInfo.Local) = 12/22/2012 8:00:00 AM

   3:

   4: TimeZoneInfo.ConvertTimeToUtc(endOfTheWorld1,TimeZoneInfo.Local) = 12/21/2012 4:00:00 PM

   5: TimeZoneInfo.ConvertTimeToUtc(endOfTheWorld2,TimeZoneInfo.Local) = 12/21/2012 4:00:00 PM

image ConvertTimeFromUtc和ConvertTimeToUtc方法在转换的时候,如果发现被转换的时间和需要转化时间具有相同的 DateTimeKind会抛出异常。也就是说,我们不能调用ConvertTimeFromUtc方法并传入DateTimeKind.Local时 间,也不能调用ConvertTimeToUtc方法并传入DateTimeKind.Urc时间。如右图所式,我们将一个 DateTimeKind.Utc时间(DateTime.UtcNow)传入ConvertTimeToUtc方法,结果抛出一个 ArgumentException异常。错误消息为:“The conversion could not be completed because the supplied DateTime did not have the Kind property set correctly.  For example, when the Kind property is DateTimeKind.Local, the source time zone must be TimeZoneInfo.Local.
Parameter name: sourceTimeZone”。

TimeZoneInfo是我们解决在开篇提出的“如何在分布式应用中处理跨时区时间处理问题”的关键,具体的解决方案,请听下回分解。

[转载]Visual Studio 2010 所有版本 下载,激活,序列号,注册码,下载地址(全集)

mikel阅读(986)

[转载]Visual Studio 2010 所有版本 下载,激活,序列号,注册码,下载地址(全集) – 醒了又睡的鱼.net的空间 – 博客园.

Visual Studio 2010 下载,安装,激活,序列号,注册码,下载地址(全集) 附Visual Studio 2008下载地址 激活 sp1下载

Visual Studio 2010 激活码 Visual Studio 2010注册码
YCFHQ-9DWCY-DKV88-T2TMH-G7BHP
破 解方式:Product Key为YCFHQ9DWCYDKV88T2TMHG7BHP,用这个key替换安装盘中setup目录中的setup.sdb中[Product Key]的内容,重新保存即可,这是针对Visual Studio 2010 Ultimate版,其他版本的应该也适用,之后的安装就一路顺风了

custom fabric

1、Microsoft Visual Studio 2010 Ultimate的安装与下载

标题:Microsoft Visual Studio 2010 Ultimate – ISO

文件名:X16-42552VS2010UltimTrial1.iso 容量:2283.0 MB SHA-1: 0×8371f6a8d090063fcc320617e94854374633df3c

网页地址:http://www.microsoft.com/downloads/details.aspx?FamilyID=06a32b1c-80e9-41df-ba0c-79d56cb823f7&displaylang=en

下载地址:http://download.microsoft.com/download/2/4/7/24733615-AA11-42E9-8883-E28CDCA88ED5/X16-42552VS2010UltimTrial1.iso

2、Microsoft Visual Studio 2010 Ultimate的注册与破解

Help->Register Product-> 注册码 YCFHQ-9DWCY-DKV88-T2TMH-G7BHP

Visual Studio 2010 下载地址 Visual Studio 2010 下载 Visual Studio 2010 中文下载

专业版(Professional)
http://download.microsoft.com/download/4/0/E/40EFE5F6-C7A5-48F7-8402-F3497FABF888/X16-42555VS2010ProTrial1.iso

高级版(Premium)
http://download.microsoft.com/download/F/F/8/FF8C8AF1-D520-4027-A844-8EC7BC0FB27C/X16-42546VS2010PremTrial1.iso
旗舰版(Ultimate)
http://download.microsoft.com/download/2/4/7/24733615-AA11-42E9-8883-E28CDCA88ED5/X16-42552VS2010UltimTrial1.iso
测试专业版(Test Professional)
LicenseKey注册码=6F0510EB-FF8F-47ec-96E1-78FB4B955330

Visual Studio 2010 Professional 官方试用版内置序列号:
[Product Key]序列号
Q49M2-C79JF-QP93Q-WX9GJ-6TKKD
Visual Studio 2010 Professional 正式序列号:(已安装测试可用。Professional版与Ultimate版均测试通过!)
YCFHQ-9DWCY-DKV88-T2TMH-G7BHP

Visual Studio 2010 Ultimate 官方试用版内置序列号:
[Product Key]序列号
YR3W8-FCM2B-7BKF9-HMQFT-CH7WK

下载了官方试用版的同学,安装后可以通过添加删除程序对Visual Studio 2010进行序列号更换。
或者修改安装光盘中setup目录下的setup.sdb文件,做一次安装激活。

MSDN官网上公布的Visual Studio 2010 SHA1及CRC:
File Name: en_visual_studio_2010_ultimate_x86_dvd_509116.iso
Date Published (UTC): 4/12/2010 8:53:48 AM
Last Updated (UTC): 4/12/2010 10:44:43 AM
SHA1: 84C90BB02AF92347010FF9058E0A2BA28F19CC53
ISO/CRC: B22E6250

File Name: en_visual_studio_2010_premium_x86_dvd_509357.iso
Date Published (UTC): 4/12/2010 8:53:23 AM
Last Updated (UTC): 4/12/2010 10:44:31 AM
SHA1: A4E69966496AD0F704FE9D97FAC2A723EF75A99B
ISO/CRC: D314471B

File Name: en_visual_studio_2010_professional_x86_dvd_509727.iso
Date Published (UTC): 4/12/2010 8:53:35 AM
Last Updated (UTC): 4/12/2010 10:44:19 AM
SHA1: F0ED50712D83BF0EDA7D284DA76DF49E4C88CEF7
ISO/CRC: 6D4DCAE4

Visual Studio 2008

1、Visual Studio 2008 Team Suite Edition的安装与下载

标题:Visual Studio Team System 2008 Team Suite (90-day Trial)

文件名:VS2008TeamSuiteENU90DayTrialX1429235.iso  容量:3921.2 MB

网页地址:http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=d95598d7-aa6e-4f24-82e3-81570c5384cb

下载地址:http://download.microsoft.com/download/d/8/9/d89c9839-ac45-4a6c-b25f-2f60b190e356/VS2008TeamSuiteENU90DayTrialX1429235.iso

2、Visual Studio 2008 Team Suite Edition的注册与破解

方法1:安装完90天试用版后,在“添加或删除应用程序”,删除vs 2008,点击“卸载”,在卸载里有让输入序列号的地方,把正式版的序列号PYHYP-WXB3B-B2CCM-V9DX9-VDY8T输入进去就行了。

方法2:把iso文件中的setup文件夹中的setup.sdb文件中的[Product Key]下的一行的原来的序列号换为能用的正式版的序列号就行了。
[Product Key]序列号
PYHYPWXB3BB2CCMV9DX9VDY8T
3、Microsoft Visual Studio 2008 Service Pack 1安装与下载

标题:Microsoft Visual Studio 2008 Service Pack 1 (iso)

文件名:VS2008SP1ENUX1512962.iso 容量:831.3 MB

网页地址:http://www.microsoft.com/downloads/details.aspx?familyid=27673C47-B3B5-4C67-BD99-84E525B5CE61&displaylang=en

下载地址:http://download.microsoft.com/download/a/3/7/a371b6d1-fc5e-44f7-914c-cb452b4043a9/VS2008SP1ENUX1512962.iso

[转载]C#.NET常用的小函数方法集

mikel阅读(1003)

[转载]C#.NET常用的小函数方法集 – 上天入地 – 博客园.

1、DateTime  数字型
System.DateTime currentTime=new System.DateTime();
1.1 取当前年月日时分秒
currentTime=System.DateTime.Now;
1.2 取当前年
int 年=currentTime.Year;
1.3 取当前月
int 月=currentTime.Month;
1.4 取当前日
int 日=currentTime.Day;
1.5 取当前时
int 时=currentTime.Hour;
1.6 取当前分
int 分=currentTime.Minute;
1.7 取当前秒
int 秒=currentTime.Second;
1.8 取当前毫秒
int 毫秒=currentTime.Millisecond;
(变量可用中文)

2、Int32.Parse(变量)      Int32.Parse(“常量”)
字符型转换 转为32位数字型

3、 变量.ToString()
字符型转换 转为字符串
12345.ToString(“n”);    //生成  12,345.00
12345.ToString(“C”);    //生成 ¥12,345.00
12345.ToString(“e”);    //生成 1.234500e+004
12345.ToString(“f4”);    //生成 12345.0000
12345.ToString(“x”);     //生成 3039 (16进制)
12345.ToString(“p”);     //生成 1,234,500.00%

4、变量.Length 数字型
取字串长度:
如: string str=”中国”;
int Len = str.Length ;  //Len是自定义变量, str是求测的字串的变量名

5、System.Text.Encoding.Default.GetBytes(变量)
字码转换 转为比特码
如:byte[] bytStr = System.Text.Encoding.Default.GetBytes(str);
然后可得到比特长度:
len = bytStr.Length;

6、System.Text.StringBuilder(“”)
字符串相加,(+号是不是也一样?)
如:System.Text.StringBuilder sb = new System.Text.StringBuilder(“”);
sb.Append(“中华”);
sb.Append(“人民”);
sb.Append(“共和国”);

7、变量.Substring(参数1,参数2);
截取字串的一部分,参数1为左起始位数,参数2为截取几位。
如:string s1 = str.Substring(0,2);

8、String user_IP=Request.ServerVariables[“REMOTE_ADDR”].ToString();
取远程用户IP地址

9、穿过代理服务器取远程用户真实IP地址:
if(Request.ServerVariables[“HTTP_VIA”]!=null){
string user_IP=Request.ServerVariables[“HTTP_X_FORWARDED_FOR”].ToString();
}else{
string user_IP=Request.ServerVariables[“REMOTE_ADDR”].ToString();
}

10、 Session[“变量”];
存取Session值;
如,赋值: Session[“username”]=”小布什”;

取值: Object objName=Session[“username”];
String strName=objName.ToString();
清空: Session.RemoveAll();

11、String str=Request.QueryString[“变量”];
用超链接传送变量。
如在任一页中建超链接:<a href=Edit.aspx?fbid=23>点击</a>
在Edit.aspx页中取值:String str=Request.QueryString[“fdid”];

12、DOC对象.CreateElement(“新建节点名”);
创建XML文档新节点

13、父节点.AppendChild(子节点);
将新建的子节点加到XML文档父节点下

14、 父节点.RemoveChild(节点);
删除节点

15、Response
Response.Write(“字串”);
Response.Write(变量);
向页面输出。

Response.Redirect(“URL地址”);
跳转到URL指定的页面

16、char.IsWhiteSpce(字串变量,位数)——逻辑型
查指定位置是否空字符;
如:
string str=”中国 人民”;
Response.Write(char.IsWhiteSpace(str,2)); //结果为:True, 第一个字符是0位,2是第三个字符。

17、char.IsPunctuation(‘字符’) –逻辑型
查字符是否是标点符号
如:Response.Write(char.IsPunctuation(‘A’));  //www.qichepeijian.com返回:False

18、(int)’字符’
把字符转为数字,查代码点,注意是单引号。
如:
Response.Write((int)’中’);  //结果为中字的代码:20013

19、(char)代码
把数字转为字符,查代码代表的字符。
如:
Response.Write((char)22269);  //返回“国”字。

20、 Trim()
清除字串前后空格

21 、字串变量.Replace(“子字串”,”替换为”)
字串替换
如:
string str=”中国”;
str=str.Replace(“国”,”央”); //www.qichepeijian.com将国字换为央字
Response.Write(str);   //输出结果为“中央”

再如:(这个非常实用)

string str=”这是<script>脚本”;
str=str.Replace(“<“,”<font><</font>”); //将左尖括号替换 为<font> 与 < 与 </font> (或换为<,但估计经XML存诸后,再提出仍会还原)
Response.Write(str); //显示为:“这是<script>脚本”

如果不替换,<script>将不显示,如果是一段脚本,将运行;而替换后,脚本将不运行。
这段代码的价值在于:你可以让一个文本中的所有HTML标签失效,全部显示出来,保护你的具有交互性的站点。
具体实现:将你的表单提交按钮脚本加上下面代码:
string strSubmit=label1.Text;  //label1是你让用户提交数据的控件ID。
strSubmit=strSubmit.Replace(“<“,”<font><</font>”);
然后保存或输出strSubmit。
用此方法还可以简单实现UBB代码。

22、Math.Max(i,j)
取i与j中的最大值
如 int x=Math.Max(5,10); // x将取值 10

[转载]使用ATL开发ActiveX控件

mikel阅读(1271)

[转载]使用ATL开发ActiveX控件 – {CODE @CODING完美世界 – 博客园.

本文描述了使用ATL开发一个ActiveX控件的完整过程。

一、创建项目

单击起始页中的“New Project…”,选择“ATL”分类下的“ATL Project”项目,项目名称为“Calculator”。在随后出现的项目向导中,使用默认配置即可。

image

二、添加控件

在解决方案管理器中的项目上右击,依次选择“Add”、“Class”,在添加类对话框中选择ATL分类下的ATL Control类型。单击“Add”按钮,将会出现添加ATL Control向导。

image

image

在向导的第二步中,将接口类型选择为“Dual”,为控件支持事件做为准备,在Support选项中,选中“Connection points”复选框。

随后出现选择控件要实现的接口的界面,除VS默认添加的实现外,再添加IObjectSafety接口,实现该接口可以避免控件在IE中使用时IE弹出运行的脚本不安全的提示。

image

三、为控件添加并实现方法

在Class View窗口中右击ICalc接口,依次选择“Add”、“Add Method…”,此处假定我们实现一个加法运算,将方法命名为“Add”,然后添加参数:

image

需要注意的是对返回值的处理。应将参数类型选定为DOUBLE*,并选中“retval”复选框。

向导结束后,VS自动在Calc.cpp中添加了该方法的空实现,略加修改后的方法代码为:

STDMETHODIMP CCalc::Add(DOUBLE a, DOUBLE b, DOUBLE* result)
{
	*result = a + b;

	return S_OK;
}

测试该方法:

由于只是调用该控件进行加法运算,并不需要该控件的界面展示,因此在测试控件之前,可以将VS自动生成的OnDraw方法中的其他代码删除,直接返回 S_OK 即可。

对VS自动生成的用于测试的htm略做修改来测试添加的方法。修改后的完整htm代码如下:

<HTML>
<HEAD>
<TITLE>ATL 8.0 test page for object Calc</TITLE>
</HEAD>
<BODY>

<OBJECT ID="Calc" CLASSID="CLSID:59443E6F-7B99-4F75-A7AF-6FEE5B8208CD"></OBJECT>

<input type="button" value="Add" onclick="add();" />

<script type="text/javascript">
    function add() {
        var calc = document.getElementById('Calc');
        var result = calc.Add(2, 3);
        alert(result);
    }
</script>

</BODY>
</HTML>

点击“Add”按钮后的运行效果:

image

四、为控件添加事件

假定控件进行的是一个非常复杂的运算,为了在调用运算时不阻塞调用者线程,可以使用异步方式完成运算。控件在完成运算时需要通知调用者,这时便需要事件。

首先按照步骤三中的方法,添加一个异步调用加法运算的方法AddAsync,然后为控件添加运算完成的事件AddCompleted。

在Class View窗口中右击_ICalcEvents接口,依次选择“Add”、“Add Method…”,根据添加方法向导添加AddCompleted方法,如下图所示:

image

然后在Class View窗口中右击CCalc类,依次选择“Add”、“Add Connection Point…”,在弹出的实现连接点窗口中实现_ICalcEvents接口。

image

完成向导后,VS会自动为我们生成基本框架,包括引发事件的方法Fire_AddCompleted。我们只需在AddAsync方法中添加运算并在运算结束时调用Fire_AddCompleted的代码:

STDMETHODIMP CCalc::AddAsync(DOUBLE a, DOUBLE b)
{
	double result;
	result = a + b;
	Fire_AddCompleted(&result);

	return S_OK;
}

在网页中添加异步计算的代码进行测试(添加的JavaScript代码如下),应该能够得到我们想要的效果。

<script type="text/javascript">
    function addAsync() {
        var calc = document.getElementById('Calc');
        calc.attachEvent("AddCompleted", OnAddCompleted);
        calc.AddAsync(3, 4);
    }

    function OnAddCompleted(result) {
        alert(result);
    }
</script>

五、ActiveX控件的事件与多线程

细心的读者一定会发现步骤四中所谓的“异步”是假的:虽然在运算结束后使用事件对调用者进行通知,但由于运算是在主线程上进行的,所以调用过程仍是同步的。步骤四其实只是展示了一下事件的简单用法,如果真正实现异步,则需要在控件中使用多线程。

在ActiveX控件中使用多线程时需要注意的是:引发事件(即调用Fire_XXXX)必须在窗口线程中进行,否则会导致事件不能被 ActiveX控件的容器处理。如果事件发生时执行代码的线程不是窗口线程。那么应该使用PostMessage或SendMessage来通知窗口线 程,并在消息处理函数中执行Fire_XXXX。为了使用控件的消息机制,还应该在CCalc的构造函数中将m_bWindowOnly字段设置为 TRUE。

以下是改为多线程后的部分示例代码:

STDMETHODIMP CCalc::AddAsync(DOUBLE a, DOUBLE b)
{
	m_a = a;
	m_b = b;

	_beginthreadex(NULL, NULL, AddMethod, this, NULL, NULL);

	return S_OK;
}

unsigned __stdcall CCalc::AddMethod(LPVOID arg)
{
	CCalc* pThis = (CCalc*)arg;
	pThis->m_result = pThis->m_a + pThis->m_b;

	pThis->SendMessage(WM_ADDCOMPLETED);

	return 0;
}

LRESULT CCalc::OnAddCompleted(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	Fire_AddCompleted(&m_result);

	return 0;
}

至此,一个简单的ActiveX控件就开发完成了。关于ActiveX控件的打包部署等问题,请关注《使用ATL开发ActiveX控件 – 控件的打包部署》。

本文示例所使用的开发环境为Visual Studio 2010。

[转载]SQL Server时间算法总结

mikel阅读(1027)

[转载]SQL Server时间算法总结 – Face Code,Brain bloom – 博客园.

   1:  DECLARE @Date  DATETIME
   2:  SET @Date=GETDATE()
   3:  --前一天,给定日期的前一天
   4:  SELECT DATEADD(DAY,-1,@Date) AS '前一天'
   5:  --后一天,给定日期的后一天
   6:  SELECT DATEADD(DAY,1,@Date) AS '后一天'
   7:  GO
   8:  
   9:  
  10:  --月初,计算给定日期所在月的第一天
  11:  --这个计算的技巧是先计算当前日期到“1900-01-01”的时间间隔数,然后把它加到“1900-01-01”上来获得特殊的日期,这个技巧可以用---来计算很多不同的日期。
  12:  DECLARE @Date  DATETIME
  13:  SET @Date=GETDATE()
  14:  SELECT DATEADD(MONTH,DATEDIFF(MONTH,'1900-01-01',@Date),'1900-01-01') AS '所在月的第一天'
  15:  --精简算法,根据SQL Server的时间表示方式可知,'1900-01-01' 可以用0代替
  16:  SELECT DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0) AS '所在月的第一天'
  17:  --上面两种算法精确到天 时分秒均为00:00:00.000
  18:  --下面算法课以保留时分秒
  19:  --思路:用给定日期减去月第一天与给定日期差的天数
  20:  SELECT DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)
  21:  GO
  22:  
  23:  --月末,计算给定日期所在月的最后一天
  24:  DECLARE @Date  DATETIME
  25:  SET @Date=GETDATE()
  26:  --思路:当前月的下一月1号在减1天
  27:  SELECT DATEADD(DAY,-1,DATEADD(MONTH,1+DATEDIFF(MONTH,'1900-01-01',@Date),'1900-01-01')) AS '所在月的最一天'
  28:  SELECT DATEADD(MONTH,1+DATEDIFF(MONTH,'1900-01-01',@Date),'1900-01-01')-1 AS '所在月的最一天'
  29:  --1900-01-01 用0代替
  30:  SELECT DATEADD(DAY,-1,DATEADD(MONTH,1+DATEDIFF(MONTH,0,@Date),0)) AS '所在月的最一天'
  31:  SELECT DATEADD(MONTH,1+DATEDIFF(MONTH,0,@Date),0)-1 AS '所在月的最一天'
  32:  --思路:与月初计算思路相同
  33:  SELECT DATEADD(MONTH,DATEDIFF(MONTH,'1989-12-31',@Date),'1989-12-31') AS '所在月的最一天'
  34:  --精简算法,'1989-12-31' 用-1代替
  35:  SELECT DATEADD(MONTH,DATEDIFF(MONTH,-1,@Date),-1) AS '所在月的最一天'
  36:  --保留时分秒的算法
  37:  SELECT DATEADD(DAY,-1,DATEADD(MONTH,1,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)))
  38:  GO
  39:  
  40:  --其他月计算
  41:  
  42:  --计算给定日期所在月的上月第一天
  43:  DECLARE @Date  DATETIME
  44:  SET @Date=GETDATE()
  45:  --当前月第一天减去一个月
  46:  SELECT DATEADD(MONTH,-1,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0)) AS '上月第一天'
  47:  --简化
  48:  SELECT DATEADD(MONTH,DATEDIFF(MONTH,0,@Date)-1,0) AS '上月第一天'
  49:  --另一种当前月第一天算法
  50:  SELECT DATEADD(MONTH,-1,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)) '上月第一天'
  51:  GO
  52:  
  53:  --计算给定日期所在月的上月最后一天
  54:  DECLARE @Date  DATETIME
  55:  SET @Date=GETDATE()
  56:  --当前月第一天减去一天
  57:  SELECT DATEADD(DAY,-1,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0)) AS '上月最后一天'
  58:  --另一种当前月第一天算法
  59:  SELECT DATEADD(DAY,-1,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)) '上月最后一天'
  60:  SELECT DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)-1 '上月最后一天'
  61:  --另一种算法,不能用当前月的最后一天加一个月,因为当前月可能是30天。
  62:  --例如 SELECT DATEADD(MONTH,1,'2010-06-30') --结果是2010-07-30而不是2010-07-31,
  63:  --这也是月末算法采用下月第一天减1天计算的原因
  64:  --但是如果计算月是31天择无此问题
  65:  --例如 SELECT DATEADD(MONTH,1,'2010-05-31') --结果是2010-06-30
  66:  --因此下面算法是正确的,-1 表示'1899-12-31 00:00:00.000'-- SELECT CONVERT(DATETIME,-1)  
  67:  SELECT DATEADD(MONTH,DATEDIFF(MONTH,-1,@Date)-1,-1)
  68:  --另一种当前月算法
  69:  SELECT DATEADD(DAY,-1,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)) '上月最后一天'
  70:  --简化
  71:  SELECT DATEADD(DAY,0-DATEPART(DAY,@Date),@Date) '上月最后一天'
  72:  GO
  73:  
  74:  --计算给定日期所在月的下月第一天
  75:  DECLARE @Date  DATETIME
  76:  SET @Date=GETDATE()
  77:  --当前月第一天加一个月
  78:  SELECT DATEADD(MONTH,1,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0)) AS '下月第一天'
  79:  --简化
  80:  SELECT DATEADD(MONTH,DATEDIFF(MONTH,0,@Date)+1,0) AS '下月第一天'
  81:  --另一种当前月第一天算法
  82:  SELECT DATEADD(MONTH,1,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date)) '下月第一天'
  83:  GO
  84:  
  85:  --计算给定日期所在月的下月最后一天
  86:  DECLARE @Date  DATETIME
  87:  SET @Date=GETDATE()
  88:  --当前月第一天加2个月再减去1天
  89:  SELECT DATEADD(DAY,-1,DATEADD(MONTH,2,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0))) AS '下月最后一天'
  90:  --简化
  91:  SELECT DATEADD(DAY,-1,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date)+2,0)) AS '下月最后一天'
  92:  SELECT DATEADD(MONTH,DATEDIFF(MONTH,0,@Date)+2,0)-1 AS '下月最后一天'
  93:  --另一种算法
  94:  SELECT DATEADD(MONTH,DATEDIFF(MONTH,-1,@Date)+1,-1) '下月最后一天'
  95:  --另一种当前月第一天算法
  96:  SELECT DATEADD(DAY,-1,DATEADD(MONTH,2,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date))) '下月最后一天'
  97:  GO
  98:  
  99:  --所在星期的第一天,计算给定日期所在星期的第1天(星期日为第一天)
 100:  DECLARE @Date  DATETIME
 101:  SET @Date= GETDATE()
 102:  --与SQL Server语言版本相关的算法
 103:  --思路:当前日期+星期日(每周的第1天)与当前日期的差的天数
 104:  --DATEPART(WEEKDAY,DATE)的返回值与@@DATEFIRST相关
 105:  SET DATEFIRST 7 -- 或者设置为美国英语SET LANGUAGE us_english; (星期日为第一天) 
 106:  SELECT DATEADD(WEEKDAY,1-DATEPART(WEEKDAY,@Date),@Date) AS '所在星期的第一天,星期日'
 107:  --星期日,与SQL Server语言版本或@@DATEFIRST无关
 108:  --'1989-12-31' 是星期日,'1989-12-31' 再加上(当前日期与1989-12-31差的星期数)个星期
 109:  SELECT DATEADD(WEEK,DATEDIFF(WEEK,-1,@Date),-1) AS '所在星期的星期日'
 110:  --或者
 111:  SELECT DATEADD(WEEK,DATEDIFF(WEEK,6,@Date),6) AS '所在星期的星期日'
 112:  GO
 113:  
 114:  
 115:  --所在星期的第二天,计算给定日期所在星期的第2天(星期日为第一天)
 116:  DECLARE @Date  DATETIME
 117:  SET @Date= GETDATE()
 118:  --思路:当前日期+星期一(每周的第2天)与当前日期的差的天数
 119:  --DATEPART(WEEKDAY,DATE)的返回值与@@DATEFIRST相关
 120:  SET DATEFIRST 7 -- 或者设置为美国英语SET LANGUAGE us_english; (星期日为第一天) 
 121:  SELECT DATEADD(DAY,2-DATEPART(WEEKDAY,@Date),@Date) AS '所在星期的第二天,星期一'
 122:  --星期一,与SQL Server语言版本或@@DATEFIRST无关
 123:  --'1900-01-01' 是星期一,'1900-01-01' 再加上(当前日期与1900-01-01差的星期数)个星期
 124:  SELECT DATEADD(WEEK,DATEDIFF(WEEK,0,@Date),0) AS '所在星期的星期一'
 125:  GO
 126:  
 127:  --上个星期第一天,计算给定日期所在星期的上一个星期日(星期日为第一天)
 128:  DECLARE @Date  DATETIME
 129:  SET @Date= GETDATE()
 130:  --思路:当前日志所在星期的星期日再减1周
 131:  --DATEPART(WEEKDAY,DATE)的返回值与@@DATEFIRST相关
 132:  SET DATEFIRST 7 -- 或者设置为美国英语SET LANGUAGE us_english; (星期日为第一天) 
 133:  SELECT DATEADD(WEEK,-1,DATEADD(DAY,1-DATEPART(WEEKDAY,@Date),@Date)) AS '上个星期第一天,星期日'
 134:  --一周等于7天
 135:  SELECT DATEADD(DAY,-7,DATEADD(DAY,1-DATEPART(WEEKDAY,@Date),@Date)) AS '上个星期第一天,星期日'
 136:  --简化
 137:  SELECT DATEADD(DAY,-6-DATEPART(WEEKDAY,@Date),@Date) AS '上个星期第一天,星期日'
 138:  --上个星期日,与SQL Server语言版本或@@DATEFIRST无关
 139:  SELECT DATEADD(WEEK,-1+DATEDIFF(WEEK,-1,@Date),-1) AS '上个星期日'
 140:  --或者
 141:  SELECT DATEADD(WEEK,DATEDIFF(WEEK,6,@Date),-1) AS '上个星期日'
 142:  GO
 143:  
 144:  
 145:  --下个星期第一天,计算给定日期所在星期的下一个星期日(星期日为第一天)
 146:  DECLARE @Date  DATETIME
 147:  SET @Date= GETDATE()
 148:  --思路:当前日志所在星期的星期日再加1周
 149:  --DATEPART(WEEKDAY,DATE)的返回值与@@DATEFIRST相关
 150:  SET DATEFIRST 7 -- 或者设置为美国英语SET LANGUAGE us_english; (星期日为第一天) 
 151:  SELECT DATEADD(WEEK,1,DATEADD(DAY,1-DATEPART(WEEKDAY,@Date),@Date)) AS '下个星期第一天,星期日'
 152:  --一周等于7天
 153:  SELECT DATEADD(DAY,7,DATEADD(DAY,1-DATEPART(WEEKDAY,@Date),@Date)) AS '下个星期第一天,星期日'
 154:  --简化
 155:  SELECT DATEADD(DAY,8-DATEPART(WEEKDAY,@Date),@Date) AS '下个星期第一天,星期日'
 156:  --下个星期日,与SQL Server语言版本或@@DATEFIRST无关
 157:  SELECT DATEADD(WEEK,1+DATEDIFF(WEEK,-1,@Date),-1) AS '下个星期日'
 158:  --或者
 159:  SELECT DATEADD(WEEK,DATEDIFF(WEEK,-1,@Date),6) AS '下个星期日'
 160:  GO
 161:  
 162:  --判断给定日期是星期几
 163:  DECLARE @Date  DATETIME
 164:  SET @Date= GETDATE()
 165:  --DATEPART(WEEKDAY,DATE)的返回值与@@DATEFIRST相关
 166:  SET DATEFIRST 7 -- 或者设置为美国英语SET LANGUAGE us_english; (星期日为第一天) 
 167:  SELECT DATEPART(WEEKDAY,@Date) --返回值 1-星期日,2-星期一,3-星期二......7-星期六
 168:  --上面算法与SQL 语言版本或 @@DATEFIRST 相关
 169:  --下面算法与SQL Server语言版本或@@DATEFIRST无关
 170:  SELECT DATENAME(WEEKDAY,@Date) '星期'
 171:  GO
 172:  
 173:  
 174:  --年度计算
 175:  DECLARE @Date  DATETIME
 176:  SET @Date=GETDATE()
 177:  --年初,计算给定日期所在年的第一天
 178:  SELECT DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),0) AS '所在年的第一天'
 179:  --年末,计算给定日期所在年的最后一天
 180:  SELECT DATEADD(YEAR,DATEDIFF(YEAR,-1,@Date),-1) AS '所在年的最后一天'
 181:  --上一年年初,计算给定日期所在年的上一年的第一天
 182:  SELECT DATEADD(YEAR,DATEDIFF(YEAR,-0,@Date)-1,0) AS '所在年的上一年的第一天'
 183:  --上一年年末,计算给定日期所在年的上一年的最后一天
 184:  SELECT DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),-1) AS '所在年的上一年的最后一天'
 185:  --下一年年初,计算给定日期所在年的下一年的第一天
 186:  SELECT DATEADD(YEAR,1+DATEDIFF(YEAR,0,@Date),0) AS '所在年的下一年的第一天'
 187:  --下一年年末,计算给定日期所在年的下一年的最后一天
 188:  SELECT DATEADD(YEAR,1+DATEDIFF(YEAR,-1,@Date),-1) AS '所在年的下一年的最后一天'
 189:  GO
 190:  
 191:  --季度计算
 192:  DECLARE @Date  DATETIME
 193:  SET @Date=GETDATE()
 194:  --季度初,计算给定日期所在季度的第一天
 195:  SELECT DATEADD(QUARTER,DATEDIFF(QUARTER,0,@Date),0) AS '当前季度的第一天'
 196:  --季度末,计算给定日期所在季度的最后一天
 197:  SELECT DATEADD(QUARTER,1+DATEDIFF(QUARTER,0,@Date),-1) AS '当前季度的最后一天'
 198:  --上个季度初
 199:  SELECT DATEADD(QUARTER,DATEDIFF(QUARTER,0,@Date)-1,0) AS '当前季度的上个季度初'
 200:  --上个季度末
 201:  SELECT DATEADD(QUARTER,DATEDIFF(QUARTER,0,@Date),-1) AS '当前季度的上个季度末'
 202:  --下个季度初
 203:  SELECT DATEADD(QUARTER,1+DATEDIFF(QUARTER,0,@Date),0) AS '当前季度的下个季度初'
 204:  --下个季度末
 205:  SELECT DATEADD(QUARTER,2+DATEDIFF(QUARTER,0,@Date),-1) AS '当前季度的下个季度末'
 206:  GO
 207:  
 208:  --计算给定日期所在月的天数
 209:  DECLARE @Date DATETIME;
 210:  SET @Date = GETDATE()
 211:  --本月度第一天与下月度第一天所差的天数
 212:  SELECT DATEDIFF(DAY,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0),DATEADD(MONTH,1+DATEDIFF(MONTH,0,@Date),0))
 213:  --借助变量简化
 214:  SELECT @Date = DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0) --本月度第一天
 215:  SELECT DATEDIFF(DAY,@Date,DATEADD(MONTH,1,@Date))
 216:  --另一种思路:给定月最后一天的日期,记为本月天数
 217:  SELECT DAY(DATEADD(MONTH,DATEDIFF(MONTH,-1,@Date),-1))
 218:  GO
 219:  
 220:  --计算给定日期所在季度的天数
 221:  DECLARE @Date DATETIME;
 222:  SET @Date = GETDATE()
 223:  --本季度第一天与下季度第一天所差的天数
 224:  SELECT DATEDIFF(DAY,DATEADD(QUARTER,DATEDIFF(QUARTER,0,@Date),0),DATEADD(QUARTER,1+DATEDIFF(QUARTER,0,@Date),0))
 225:  --借助变量简化
 226:  SELECT @Date = DATEADD(QUARTER,DATEDIFF(QUARTER,0,@Date),0) --本季度第一天
 227:  SELECT DATEDIFF(DAY,@Date,DATEADD(QUARTER,1,@Date))
 228:  GO
 229:  
 230:  --计算给定日期所在年度的天数
 231:  DECLARE @Date DATETIME;
 232:  SET @Date = GETDATE()
 233:  --本年度第一天与下年度第一天所差的天数
 234:  SELECT DATEDIFF(DAY,DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),0),DATEADD(YEAR,1+DATEDIFF(YEAR,0,@Date),0))
 235:  --借助变量简化
 236:  SELECT @Date = DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),0) --本年度第一天
 237:  SELECT DATEDIFF(DAY,@Date,DATEADD(YEAR,1,@Date))
 238:  GO
 239:  
 240:  --判断给定日期所在年是否闰年
 241:  --根据全年总天数判断
 242:  DECLARE @Date DATETIME;
 243:  SET @Date = GETDATE()
 244:  SELECT CASE DATEDIFF(DAY,DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),0),DATEADD(YEAR,1+DATEDIFF(YEAR,0,@Date),0))
 245:    WHEN 365 THEN '平年' ELSE '闰年' END
 246:  --根据二月天数判断
 247:  --给日期的上一年最后一天加2个月,即为当年2月最后一天
 248:  SELECT CASE DAY(DATEADD(MONTH,2,DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),-1))) WHEN 28 THEN '平年' ELSE '闰年' END
 249:  GO
 250:  
 251:  --计算给定日期是当年的第几天
 252:  DECLARE @Date DATETIME;
 253:  SET @Date = GETDATE()
 254:  SELECT DATEPART(DAYOFYEAR,@Date) [DayOfYear];
 255:  SELECT DATENAME(DAYOFYEAR,@Date)  [DayOfYear];
 256:  --另一种思路:当前日期与上年最后一天差的天数
 257:  SELECT DATEDIFF(DAY,DATEADD(YEAR,DATEDIFF(YEAR,0,@Date),-1),@Date)[DayOfYear]
 258:  GO
 259:  
 260:  --计算给定日期是当年的第几周
 261:  DECLARE @Date DATETIME;
 262:  SET @Date = GETDATE()
 263:  SELECT DATEPART(WEEK,@Date) [WeekOfYear]; --返回int型
 264:  SELECT DATENAME(WEEK,@Date) [WeekOfYear]; --返回varchar型
 265:  GO
 266:  
 267:  --计算给定日期是当年的第几月
 268:  DECLARE @Date DATETIME;
 269:  SET @Date = GETDATE()
 270:  SELECT DATEPART(MONTH,@Date) [MonthOfYear]; --返回int型
 271:  SELECT DATENAME(MONTH,@Date) [MonthOfYear]; --返回varchar型
 272:  SELECT MONTH(@Date) [MonthOfYear];--返回int型
 273:  GO
 274:  
 275:  --计算给定日期是当年的第几季度
 276:  DECLARE @Date DATETIME;
 277:  SET @Date = GETDATE()
 278:  SELECT DATEPART(QUARTER,@Date) [QuarterOfYear]; --返回int型
 279:  SELECT DATENAME(QUARTER,@Date) [QuarterOfYear]; --返回varchar型
 280:  GO
 281:  
 282:  --计算给定日期是当月的第几周
 283:  DECLARE @Date DATETIME;
 284:  SET @Date = GETDATE()
 285:  --思路,给定日期是当年的第几周-给定日期所在月第一天是当年的第几周
 286:  SELECT DATEPART(WEEK,@Date)-DATEPART(WEEK,DATEADD(MONTH,DATEDIFF(MONTH,0,@Date),0))+1 [WeekOfMonth]
 287:  SELECT DATEPART(WEEK,@Date)-DATEPART(WEEK,DATEADD(DAY,1-DATEPART(DAY,@Date),@Date))+1 [WeekOfMonth]
 288:  GO
 289:  
 290:  --计算给定日期所在月的第一个星期一是哪天
 291:  DECLARE @Date DATETIME;
 292:  SET @Date = GETDATE()
 293:  --思路,1900-01-01(星期一)加上(给定日志所在月的月6号与1900-01-01差的周数)个周
 294:  --为什么不选7号?如果是7号,那么7好恰好是星期日的话,第一个周一就会算到8号。
 295:  --为什么不选5号?如果5号是星期六,那么周一就跑到上月了。小于5号与这个道理一样。
 296:  SELECT DATEADD(WEEK,DATEDIFF(WEEK,0,DATEADD(DAY,6-DATEPART(DAY,@Date),@Date)),0) '所在月的第一个星期一'
 297:  SELECT DATEADD(WEEK,DATEDIFF(WEEK,0,DATEADD(DAY,6-DATEPART(DAY,@Date),@Date)),7) '所在月的第二个星期一'
 298:  SELECT DATEADD(WEEK,DATEDIFF(WEEK,0,DATEADD(DAY,6-DATEPART(DAY,@Date),@Date)),1) '所在月的第一个星期二'
 299:  SELECT DATEADD(WEEK,DATEDIFF(WEEK,0,DATEADD(DAY,6-DATEPART(DAY,@Date),@Date)),8) '所在月的第二个星期二'
 300:  GO

[转载]SQL Server中约束的介绍

mikel阅读(891)

[转载]SQL Server中约束的介绍 – 编程点滴 – 博客园.

摘要

对于SQL Server中的约束,想必大家并不是很陌生。但是约束中真正的内涵是什么,并不是很多人都很清楚的。本文以详细的文字来介绍了什么是约束,以及如何在数据库编程中应用和使用这些约束,来达到更好的编程效果。(本文部分内容参考了SQL Server联机手册)

内容

数据完整性分类
实体完整性
域完整性
引用完整性
用户定义完整性
PRIMARY KEY约束
DEFAULT约束
CHECK约束
UNIQUE约束
FOREIGN KEY约束

正文

在数据库管理系统中,保证数据库中的数据完整性是非常重要的。所谓数据完整性,就是指存储在数据库中数据的一致性和正确性。约束定义关于列中允许值 的规则,是强制完整性的标准机制。使用约束优先于使用触发器、规则和默认值。查询优化器也使用约束定义生成高性能的查询执行计划。

SQL Server联机丛书中,将数据完整性解释如下:“存储在数据库中的所有数据值均正确的状态。如果数据库中存储有不正确的数据值,则该数据库称为已丧失数据完整性。”强制数据完整性可确保数据库中的数据质量。

例如,如果输入了 employee_id 值为 123 的职员,那么该数据库不应允许其他职员使用同一 ID 值。如果计划将 employee_rating 列的值范围设定为从 1 到 5,则数据库不应接受 6。如果表有一 dept_id 列,该列存储职员的部门编号,则数据库应只允许接受公司中的有效部门编号。

数据完整性分类

在SQL Server中,根据数据完整新措施所作用的数据库对象和范围不同,可以将数据完整性分为以下几种。

实体完整性
域完整性
引用完整性
用户定义完整性

SQL Server联机丛书中指明:“对表进行计划有两个重要步骤:标识列的有效值和确定如何强制列中的数据完整性。”

实体完整性

实体完整性简单的说,就是将表中的每一行看作一个实体。实体完整性要求表的标示符列或主键的完整性。可以通过建立唯一索引、PRIMARY KEY约束、UNIQUE约束,以及列的IDENTITY属性来实施实体完整性。

域完整性

域完整性是指给定列的输入有效性。要求表中指定列的数据具有正确的数据类型、格式和有效的数据范围。强制域有效性的方法有:限制类型(通过数据类 型)、格式(通过 CHECK 约束和规则)或可能值的范围。域完整性通过 FOREIGN KEY 约束、CHECK 约束、DEFAULT 定义、NOT NULL 定义和规则来实现。

引用完整性

引用完整性又称参照完整性。引用完整性维持被参照表和参照表之间的数据一致性,他通过主键(PRIMARY KEY)约束和外键(FOREIGN KEY)约束来实现。引用完整性确保键值在所有表中一致。这样的一致性要求不能引用不存在的值,如果键值更改了,那么在整个数据库中,对该键值的所有引用 要进行一致的更改。在被参照表中,当其主键值被其他表所参照时,该行不能被删除也不允许改变。在参照表中,不允许参照不存在的主键值。

强制引用完整性时,SQL Server 禁止用户进行下列操作:

当主表中没有关联的记录时,将记录添加到相关表中。
更改主表中的值并导致相关表中的记录孤立。
从主表中删除记录,但仍存在与该记录匹配的相关记录。

例如,对于 pubs 数据库中的 sales 和 titles 表,引用完整性基于 sales 表中的外键 (title_id) 与 titles 表中的主键 (title_id) 之间的关系。

用户定义完整性

用户定义完整性使您得以定义不属于其它任何完整性分类的特定业务规则。所有的完整性类型都支持用户定义完整性。

建立和使用约束的目的是保证数据的完整性,约束是SQL Server强制实行的应用规则,他能够限制用户存放到表中数据的格式和可能值。约束作为数据库定义的一部分在CREATE TABLE语句中声明,所以又称做声明完整性约束。约束独立于表结构,可以在不改变表结构情况下,通过ALTER TABLE语句来添加或者删除。在删除一个表时,该表所带的所有约束定义也被随之删除。

PRIMARY KEY约束

在数据库的每个表中,经常有通过一列或者多个列,唯一的标识表中的每一行。就好像我们平时使用的身份证,能够唯一的标识每个人一样。这样的一列或者多个列,被称为主键,通过主键,可以强制表的实体完整性。

每一个表中只有一个PRIMARY KEY约束,更简单的说,他是通过建立唯一索引保证指定列的实体完整性。在使用PRIMARY KEY约束时,该列的空值属性必须定义为NOT NULL,也就是说拥有主键的那一列,不能为空。

由于PRIMARY KEY约束确保唯一数据,所以经常用来定义标识列。标识列就是表中已经指派了标识属性的列。标识属性生成唯一数字。

有些刚刚开始接触SQL Server编程的技术爱好者通常会有这样的疑问,为什么非要在一个表里面建立主键?其实答案是很明显的,建立主键不仅可以保证表内数据的完整性,而且在为表建立主键的同时,Microsoft SQL Server能够通过为主键创建唯一索引强制数据的唯一性。

当在查询中使用主键时,也就是利用主键所在的列作为关键字进行查询,该所因还可以用来对数据进行快速访问。如果在PRIMARY KEY约束中未指定索引类型时,默认情况下所建立的索引为簇索引。该索引只能通过删除PRIMARY KEY约束或其相关表的方法来删除,而不能使用DROP INDEX语句删除。当PRIMARY KEY约束由另一张表的FOREIGN KEY约束引用时,不能删除PRIMARY KEY约束;要删除它,必须先删除FOREIGN KEY约束。

通常建立一列约束时,我们称之为列级PRIMARY KEY约束,应用于多列时,称之为表级PRIMARY KEY约束。

列级PRIMARY KEY约束的定义格式为:

[CONSTRAINT constraint_name]
PRIMARY KEY [CLUSTERED | NONCLUSTERED]
[WITH [FILLFACTOR = fillfactor]]
[ON {filegroup | DEFAULT}]

表级PRIMARY KEY约束定义风格为:

[CONSTRAINT constraint_name]
PRIMARY KEY [CLUSTERED | NONCLUSTERED]
{(column[,…n])}
[WITH [FILLFACTOR = fillfactor]]
[ON {filegroup | DEFAULT}]

在上面的PRIMARY KEY约束定义中,WITH子句设置为PRIMARY KEY约束所建立索引的页面填充度,ON子句指出存储索引的数据库文件组名称。将索引文件和表数据文件分寸到数据库中位于不同硬盘驱动器的数据文件中,有利于减轻单个硬盘的负载。

DEFAULT约束

使用DEFAULT约束,如果用户在插入新行是没有显示为列提供数据,系统会将默认支赋给该列。例如,在一个表的payterms列中,可以让数据 库服务器在用户没有输入时填上”???”或者”fill in later”。默认值约束所提供的默认值约束所提供的默认值可以为常量、函数、系统零进函数、空值(NULL)等等。零进函数包括 CURRENT_TIMESTAMP、SYSTEM_USER、CURRENT_USER、USER和SESSION_USER等。默认值约束的定义格式 为:

[CONSREAINT constraint_name]
DEFAULT constant_expression

其中,constraint_name参数指出所建立的默认值约束名称。Constant_expression表达式为列提供默认值。在使用默认约束是,还应该注意以下两点:

1. 每列只能有一个默认约束。
2. 约束表达式不能参照表中的其他列和其他表、视图或存储过程。

CHECK约束

CHECK约束的主要作用是限制输入到一列或多列中的可能值,从而保证SQL Server数据库中数据的域完整性。例如,可以在建立用户使用库时,强制用户的密码在10位以上。每个标允许建立多个CHECK约束。在CHECK约束中可以包含搜索条件,但不能包含子查询。

同样,我们可以为表中的每个列建立约束,每个列可以拥有多个CHECK约束,但是如果使用CREATE TABLE语句,只能为每个列建立一个CHECK约束。如果CHECK约束被应用于多列时,他必须被定义为表级CHECK约束。

在表达式中,可以输入搜索条件,条件中可以包括AND或者OR一类的连接词。列级CHECK约束只能参照被约束列,而表级CHECK约束则只能参照表中列,它不能参照其他表中列。

例如,我们使用下面的语句在TB_CHECK_CONSTRAINT表中新加入一列ZIP_CODE及其相应的CHECK约束:

ALTER Table TB_CHECK_CONSTRAINT
ADD
ZIP_CODE char(6) null
CONSTRAINT CH_ZIP_CODE check
(ZIP_CODE like ‘[0-9] [0-9] [0-9] [0-9] [0-9] [0-9]’)

同样,我们可以使用CHECK或NOCHECK来打开或者关闭某个约束。例如,下面的语句将关闭上面建立的CH_ZIP_CODE约束:

ALTER Table TB_CHECK_CONSTRAINT
NOCHECK CONSTRAINT CH_ZIP_CODE

如果希望使用编辑器来建立约束关系,需要在数据库关系图中,右击包含约束的表,然后从快捷菜单中选择“约束”命令。或者可以将包含约束的表打开表设计器,在表设计器中右击,然后选择“约束”命令。

UNIQUE约束

该约束应用于表中的非主键列,UNIQUE约束保证一列或者多列的试题完整性,确保这些猎不会输入重复的值。例如,表中UserName列为主键, 但是其中还包括身份证号码列,由于所有身份证号码不可能出现重复,所以可以在此列上建立UNIQUE约束,确保不会输入重复的身份证号码。

它与PRIMARY KEY约束的不同之处在于,UNIQUE约束可以建立在多个列之上,而PRIMARY KEY约束在一个表中只能有一个。

建立UNIQUE约束,可以使用如下办法:

1. 在数据库关系图中右击将包含约束的表,然后从快捷菜单中选择”属性”命令。
-或- 为将包含约束的表打开表设计器,在表设计器中右击,然后从快捷菜单中选择”属性”命令。
2. 选择”索引/键”选项卡。
3. 选择”新建”命令。系统分配的名称出现在”索引名”框中。
4. 在”列名”下展开列的列表,选择要将约束附加到的列。若要将约束附加到多个列,在后续行中选择其它的列。
5. 选择”创建 UNIQUE”复选框。
6. 选择”约束”选项。

当保存表或关系图时,唯一约束即创建在数据库中。

当希望删除UNIQUE索引时,可以使用如下步骤:

1. 在数据库关系图中,右击包含约束列的表,然后从快捷菜单中选择”索引/键”命令。
-或- 为包含约束的表打开表设计器,在表设计器中右击,然后从快捷菜单中选择”索引/键”命令。
2. 从”选定的索引”列表中选择唯一约束。
3. 选择”删除”按钮。

同样,对于一列的UNIQUE约束,我们称之为列级UNIQUE约束,对于多列的UNIQUE约束,我们称之为表级UNIQUE约束。下面给出列级UNIQUE约束的定义格式:

[CONSTRAINT constraint_name]
UNIQUE [CLUSTERED | NONCLUSTERED]
[WITH [FILLFACTOR = fillfactor]]
[ON {filegroup | DEFAULT}]

使用UNIQUE约束的过程中,还需要注意,如果要对允许空值的列强制唯一性。可以允许空值的列附加UNIQUE约束,而只能将主键的约束附加到不允许空值的列。但UNIQUE约束不允许表中受约束列有一行以上的值同时为空。

例如,下面语句为TB_UNIQUE_CONSTRAINT表添加UNIQUE约束:

ALTER Table TB_UNIQUE_CONSTRAINT
ADD
CONSTRAINT UN_PHONE UNIQUE (username, phone)

FOREIGN KEY约束

FOREIGN KEY约束为表中的一列或者多列数据提供数据完整性参照。通常是与PRIMARY KEY约束或者UNIQUE约束同时使用的。

例如,在BookStores表中的author_id列以及title_id列分别参照了Authors表中的author_id列以及 Titles表的title_id列。在向BookStores表中插入新行或修改其中的数据时,这两列的数据值必须在Authors表和Titles表 中已经存在,否则将不能执行插入或者修改操作。

在使用FOREIGN KEY约束是,需要注意以下几点:

1. 一个表最多只能参照253个不同的数据表,每个表也最多只能有253个FOREIGN KEY约束。
2. FOREIGN KEY约束不能应用于临时表。
3. 在实施FOREIGN KEY约束时,用户必须至少拥有被参照表中参照列的SELECT或者REFERENCES权限。
4. FOREIGN KEY约束同时也可以参照自身表中的其他列。
5. FOREIGN KEY约束,只能参照本身数据库中的某个表,而不能参照其他数据库中的表。跨数据库的参照只能通过触发器来实现。

[转载]jquery.simple.tree插件,更简单,兼容性更好的无限树插件!

mikel阅读(1037)

[转载]jquery.simple.tree插件,更简单,兼容性更好的无限树插件! – 我是一只鸟,想飞飞不高! – 博客园.

在这里介绍一款小巧,功能强大,能拖拽,支持异步,且兼容性更高的JQuery Tree插件:

效果如下:

选择:

拖拽:

JQuery.simple.tree.官网地址: http://news.kg/wp-content/uploads/tree/(貌似已经打不开),不过因为操作比较简单,所以我们暂且用之。

前面讲过jquery EasyUI Tree插件,简单易用,但经过测试仍有诸多缺点,

例如:

1、兼容IE8的AJAX有问题。

2、如果异步返回数据较慢,将可能导致加载失败。

3、我们只使用其中的Tree功能,但其体积实在有点庞大。…

而我们需要的是,兼容性好,异步,体积小(用Tree的场景实在比较少,所以还是专用的代码文件比较好。)

好了,我们开始jQuery.simple.tree之旅:

首先,要加载文件,一共三个:CSS、jQuery主文件、还有其本身的js文件;

然后,是定义Tree的代码;

最后,写出这根树的根节点HTML代码;

前台代码如下:

html代码

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml” >
<head runat=”server”>
<title>区域选择</title>
<link rel=”stylesheet” href=”/js/simpletree/jQuery.simple.tree.css” />
<script type=”text/JavaScript src=”/js/jquery1.4.2.min.js”></script>
<script type=”text/JavaScript src=”/js/simpletree/jquery.simple.tree.js”></script>
<script type=”text/JavaScript>
var simpleTreeCollection;
$(document).ready(function(){
simpleTreeCollection = $(.simpleTree).simpleTree({
autoclose: true,
afterClick:function(node){
alert(您选择了: + $(span:first,node).text() + id为: + $(span:first,node).attr(id).substr(2));//此处为何要“.substr(2)”,是因为特殊原因,稍后可以得到解释.如果你仅仅需要取文字,这里可以不取ID。
},
afterDblClick:function(node){
//alert(“text-“+$(‘span:first’,node).text());//双击事件
},
afterMove:function(destination, source, pos){
//alert(“destination-“+destination.attr(‘id’)+” source-“+source.attr(‘id’)+” pos-“+pos);//拖拽事件
},
afterAjax:function()
{
//alert(‘Loaded’);
},
animate:true
//,docToFolderConvert:true
});
});
</script>
</head>
<body>
<ul class=”simpleTree”>
<li class=”root”><span>区域选择</span>
<ul>
<li id=”root0″ class=”open”><span>中国</span>
<ul class=”ajax”>
<li id=’0′>{url:/common/GetGroupHtmlByPid.ashx?pid=0}</li>
</ul>
</li>
</ul>
</li>
</ul>
</body>
</html>

后台响应代码:

GetGroupHtmlByPid.ashx.cs

public class GetGroupHtmlByPid : IHttpHandler
{
GroupManager group;
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = text/plain;
int parentId = 1;
int type = 0;
string resultStr = string.Empty;
if (!context.Request.QueryString[pid].IsNullOrEmpty())
{
Int32.TryParse(context.Request.QueryString[pid], out parentId);
}
if (!context.Request.QueryString[type].IsNullOrEmpty())
{
Int32.TryParse(context.Request.QueryString[type], out type);
}

if (parentId >= 0)
{
try
{
group = new GroupManager((GroupType)type);
var subAg = group.AllGroups.Where(c => c.ParentId == parentId);
resultStr += <ul>;
foreach (Base_group item in subAg)
{
resultStr += <li id=\“” + item.GroupId + \><span id=\1_ + item.GroupId + \> + item.GroupName + </span>;//这里可以解释前台代码为何要.substr(2);
resultStr += <ul class=’ajax’><li>{url:/common/GetGroupHtmlByPid.ashx?pid= + item.GroupId + }</li></ul>;
resultStr += </li>;
}
resultStr += </ul>;
}
catch (Exception ex)
{
}
}
context.Response.Write(resultStr);
}

public bool IsReusable
{
get
{
return false;
}
}
}

后台看起来有点别扭,因为这个插件本身只支持HTML节点加载的,不过网上有人进行扩展了,用了JSON,不过个人感觉这对速度影响实在微乎其微,还是直接封装出HTML代码的。

总结一下jquery.simple.tree插件的优缺点:

优点:体积小,兼容性高,可异步,支持拖拽。

缺点:如果初始化的时候就需要异步加载,则需要手动更改它的几行代码。例如我的例子中。

本插件还有一个特别的功能,支持拖拽,可以用于后台维护无限分类,非常方便,有待读者自己去发掘,希望本文能够抛砖引玉,对你有所帮助!

源插件下载地址:http://plugins.jquery.com/project/SimpleTree

我的修改后的下载地址:simpletree.rar

我只修改了2行代码,以便在第一次初始化时就加载异步的内容。

[转载]Asp.net中文件的压缩与解压

mikel阅读(1052)

[转载]Asp.net中文件的压缩与解压 – 清风飘过 – 博客园.

这里笔者为大家介绍在ASP.NET中使用文件的压缩与解压。在ASP.NET中使用压缩给大家带来的好处是显而易见的,首先是减小了服务器端 文件存储的空间,其次下载时候下载的是压缩文件想必也会有效果吧,特别是比较大的文件。有的客户可能会很粗心上传的是文件,那么可以通过判断后缀名来判断 文件,不是压缩文件,就可以压缩文件,在存储。

这里笔者引用了一个DLL文件(ICSharpCode.SharpZipLib.dll)(包含在本文代码中),调用其中的函数,就可以对文件进行压缩及解压了。其中压缩笔者主要用到的函数是

1 /// <summary> 2 /// 压缩文件 3 /// </summary> 4 /// <param name="fileName">要压缩的所有文件(完全路径)</param> 5 /// <param name="name">压缩后文件路径</param> 6 /// <param name="Level">压缩级别</param> 7   public void ZipFileMain(string[] filenames, string name, int Level) 8 { 9 ZipOutputStream s = new ZipOutputStream(File.Create(name)); 10 Crc32 crc = new Crc32(); 11 //压缩级别 12 s.SetLevel(Level); // 0 - store only to 9 - means best compression 13 try 14 { 15 foreach (string file in filenames) 16 { 17 //打开压缩文件 18 FileStream fs = File.OpenRead(file); 19 20 byte[] buffer = new byte[fs.Length]; 21 fs.Read(buffer, 0, buffer.Length); 22 23 //建立压缩实体 24 ZipEntry entry = new ZipEntry(System.IO.Path.GetFileName(file)); 25 26 //时间 27 entry.DateTime = DateTime.Now; 28 29 // set Size and the crc, because the information 30 // about the size and crc should be stored in the header 31 // if it is not set it is automatically written in the footer. 32 // (in this case size == crc == -1 in the header) 33 // Some ZIP programs have problems with zip files that don't store 34 // the size and crc in the header. 35 //空间大小 36 entry.Size = fs.Length; 37 fs.Close(); 38 crc.Reset(); 39 crc.Update(buffer); 40 entry.Crc = crc.Value; 41 s.PutNextEntry(entry); 42 s.Write(buffer, 0, buffer.Length); 43 } 44 } 45 catch 46 { 47 throw; 48 } 49 finally 50 { 51 s.Finish(); 52 s.Close(); 53 } 54 55 }

解压缩的主要代码

1 /// <summary> 2 /// 解压文件 3 /// </summary> 4 /// <param name="ZipPath">被解压的文件路径</param> 5 /// <param name="Path">解压后文件的路径</param> 6 public void UnZip(string ZipPath,string Path) 7 { 8 ZipInputStream s = new ZipInputStream(File.OpenRead(ZipPath)); 9 10 ZipEntry theEntry; 11 try 12 { 13 while ((theEntry = s.GetNextEntry()) != null) 14 { 15 string fileName = System.IO.Path.GetFileName(theEntry.Name); 16 17 //生成解压目录 18 Directory.CreateDirectory(Path); 19 20 if (fileName != String.Empty) 21 { 22 //解压文件 23 FileStream streamWriter = File.Create(Path + fileName); 24 25 int size = 2048; 26 byte[] data = new byte[2048]; 27 while (true) 28 { 29 size = s.Read(data, 0, data.Length); 30 if (size > 0) 31 { 32 streamWriter.Write(data, 0, size); 33 } 34 else 35 { 36 37 streamWriter.Close(); 38 streamWriter.Dispose(); 39 break; 40 } 41 } 42 43 streamWriter.Close(); 44 streamWriter.Dispose(); 45 } 46 } 47 } 48 catch 49 { 50 throw; 51 } 52 finally 53 { 54 s.Close(); 55 s.Dispose(); 56 } 57 } 58 }

那么我这里做了个简单的测试程序(点击下载

这里已知道要被压缩文件,这里只需填入要被压缩到的路径(”D:\text\”)解压路径一样。这里解压级别越大,压缩的就越厉害。

可以看测试小程序,将解压/压缩引入到你的项目中

好了,如果本文对你有作用请您留个言语,让笔者知道 ^_^

[转载]QQ窗口抓取及如何进行自动化操作

mikel阅读(1027)

[转载]QQ窗口抓取及如何进行自动化操作 – wuhuacong(伍华聪)的专栏 – 博客园.

本文在文章开始,先介绍下窗口的抓取软件,Spy++及AccExplorer32.exe,前者是大名鼎鼎的微软出品,几乎可以抓取所有的Windows窗口及控件(其实也是一个窗口),另外一个也是类似,功能可以互补一下。

首先看看两者的界面,在抓取QQ的【查找联系人/群/企业】的窗口时候的情况:


Sp++的界面


AccExplorer32.exe界面

两者界面不同,不过基本功能有重叠,Spy++提供的功能可能会更多一些,这两个软件都可以对列出的窗口进行一系列的操作,如可以找到相关的窗口信息,窗口位置,以及对各种窗口操作的信息,包括鼠标、键盘等一系列的操作都可以模拟出来,非常强大。

为 了模拟抓取窗口以及对窗口的各种操作,我们可以通过FindWindow和FindWindowEx、SendMessage、PostMessage等 Windows消息来进行处理,便可实现基本的窗口、控件操作,另外按钮的操作,我们则可以模拟鼠标单击某个坐标点的方式实现按钮的单击操作模拟。 模拟的QQ界面窗口如下所示,是一个查找窗口的。

我们通过抓取窗口信息,我们看到该窗口下面只有两个可见窗口,分别对应两个输入控件,可以发现该窗口的一个输入(账号和昵称输入框中的任何一个)的Class 名称如下所示:

首先我们来创建一个界面,如下所示,用来模拟相关的操作。

我们在辅助类中定义几个函数用来实现窗口的操作

[DllImport(user32.dll)]

private static extern IntPtr FindWindowEx(IntPtr parent, IntPtr childAfter, string className, string windowName);

[DllImport(user32.dll, EntryPoint = FindWindow)]
private static extern IntPtr FindWindowWin32(string className, string windowName);

[DllImport(user32.dll )]
public static extern int GetClassName(IntPtr hWnd, [Out] StringBuilder className, int maxCount);

[DllImport(user32.dll)]
private static extern int SendMessage(IntPtr window, int message, int wparam, int lparam);

[DllImport(user32, CharSet = CharSet.Auto)]
private extern static int SendMessage(IntPtr hWnd, int wMsg, int wParam, string lpstring);

[DllImport(user32.dll)]
private static extern int PostMessage(IntPtr window, int message, int wparam, int lparam);

在实际的按钮操作代码中,我们简化了具体的操作,只需要调用辅助类就可以了

private void btnSearch_Click(object sender, EventArgs e)

{
Win32Window win
= Win32Window.FindWindow(null, this.txtWindowName.Text);
if (win != null)
{
ArrayList list
= win.Children;
foreach (Win32Window sub in list)
{
if (sub.Visible && sub.ClassName == ATL:30A4D1D8)
{
sub.SendMessage(WindowMessage.WM_SETTEXT,
0, this.txtInput.Text);
}
}
}
int x = 288;
int y = 328;
win.ClickWindow(
left, x, y, false);
}

其中位置信息时通过Spy++监控出来的信息。

最后结果如下所示,实现控件内容的修改,并执行了单击按钮的操作,弹出添加好友确认信息。

如果要进行进一步的操作,在继续对弹出的窗口进一步分析即可,其他所有的窗口操作,原理一样,这样就可以实现很多程序的自动模拟操作,是不是很方便呢。

[转载]从一个WEB请求说开去(三)

mikel阅读(1000)

[转载]从一个WEB请求说开去(三) – 大河 – 博客园.

由于最近一段时间忙的我晕头转向,所以一直没时间继续我的WEB请求之旅,深感抱歉。

开篇之前,我必须向大家道个歉,由于我的知识水平有限,对ASP.NET没有一个系统性的认知,所以不对的地方请朋友们不吝赐教。说真的,我特别怕由于我的认知不足而误导大家,请大家一定要带着脑袋以批判的角度来阅读拙作。砖头准备好了吗?开始。

上文我们主要描述了iis6.0的两个核心组件WAS和Worker Progress,而本文重点讲述一下WEB请求在工作进程中都经历了什么,下面我把描述工作进程的图示放大,如下:

我们知道,当一个有效的WEB请求到达HTTP.SYS后,发现没有相应有效的工作进程,则HTTP.SYS会告诉WAS(svchost.exe),以 为之创建并启动一个工作进程(w3wp.exe)。在启动工作进程的过程中加载ISAPI(非托管代码)以及CLR(托管代码),然后在工作进程中创建应 用程序域。其实如上一系列操作只是为WEB请求准备好其运行环境。

当一个WEB请求进入已经准备好的工作进程边界(工作进程从HTTP.SYS的应用程序池对应的消息队列中取出该WEB请求),那此时首先会经过 ISAPI FILTER的处理,比如修改http报头和URL等,具体功能参见上文。接下来就会将处理的WEB请求交给ISAPI EXTENSION。那么ISAPI EXTENSION会干什么呢?我们先看下图:

我们从上图可以看出,它就是一个应用程序扩展名的映射,即文件扩展名与处理该文件的应用程序的一个映射表,接下来我们看看具有aspx扩展名的文件是由哪个应用程序集处理(dll)的,如下图:

看到了吗?其实也就告诉我们对于aspx扩展名的文件,要交给aspnet_isapi.dll处理,其实大部分文件都映射到了 aspnet_isapi.dll,也就是说大部分动态的web请求文件都交由程序集aspnet_isapi.dll来处理。对于静态文件比如jpg、 js、以及css等都会直接将文件返回给客户端。注意:aspnet_isapi.dll是一个非托管的Win32动态库,里面封装了很多用于与web进 行交互的函数,它的处理速度那是相当的快。另外它被加载到了工作进程中,也就是说非托管的aspnet_isapi.dll与托管的web应用都处于一个 工作进程中,这显然会加快其处理速度。跨进程访问是要付出代价的,所以我们不必为此担心。那么如何才能调用aspnet_isapi.dll提供的一系列 服务呢,这就引出了ISAPIRuntime,它的主要功能就是负责ISAPI扩展的非托管代码与托管代码之间的沟通与交互。您只要记住这点就行了,具体 实现细节我认为没必要深究。如果您对此感兴趣可以借助reflector.exe等工具进行跟踪研判。

我们的WEB请求走到到哪儿了,没错,它经过ISAPI顺利的进入到了ASP.NET通道接下来他会一直走啊走,经过HttpApplication、httphandles等经过处理后将其响应返回给http.sys,最终到达客户端浏览器。

本来关于IIS6.0还有很多说不完的话题,比如ASP.NET application的生命周期,以及web page的生命周期、以及如何自定义httpmodules,如何自定义httphandles等等,网上这方面的资料已经很多了,我也不再赘述。

其实写到此我只大概介绍了IIS6.0的三个核心组件HTTP.SYS、WAS以及Worker Progress,另外两个(Inetinfo.exe和IIS MetaBase)只是轻描淡写,如果有时间我会继续说说关于这两个核心组件的内容,另外会顺带说说SSL。

为了给大家一个关于WEB请求之旅的整体印象,我会在下一篇做个总结。如有疏漏之处还望朋友们多多海涵。