Jarody's profile三省吾身PhotosBlogListsMore Tools Help

Blog


    June 09

    080605

    两天连着接到四个朋友的电话,内容大同小异,某月某日,结婚,一定要到啊

    站在人来车往热闹非凡的街角,却有一种名为寂寞的情绪滋生

    想要找个人陪我走走

    茫然拨弄着手机,却不知道可以打给谁......
    May 13

    用C#2.0实现网络蜘蛛(WebSpider)

    本文转自CSDN,作者:李宁

    摘要:本文讨论了如何使用C#2.0实现抓取网络资源的网络蜘蛛。使用这个程序,可以通过一个入口网址(如http://www.comprg.com.cn)来扫描整个互联网的网址,并将这些扫描到的网址所指向的网络资源下载到本地。然后可以利用其他的分析工具对这些网络资源做进一步地分析,如提取关键词、分类索引等。也可以将这些网络资源作为数据源来实现象Google一样的搜索引擎。
    关键词:C#2.0,Html,网络蜘蛛, 键树,正则表达式

    一、引言

        在最近几年,以Google为首的搜索引擎越来越引起人们的关注。由于在Google出现之前,很多提供搜索服务的公司都是使用人工从网络上搜集信息,并将这些信息分类汇总后作为搜索引擎的数据源。如yahoo公司一开始就是通过数千人不停地从网上搜集供查询的信息。这样做虽然信息的分类会很人性化,也比较准确,但是随着互联网信息爆炸式地增长,通过人工的方式来搜集信息已经不可能满足网民对信息的需求了。然而,这一切随着Google的出现而得到了彻底改变。Google一反常规的做法,通过程序7*24地从网上不停地获取网络资源,然后通过一些智能算法分析这些被下载到本地的网络资源,最后将这些分析后的数据进行索引后就形成了一套完整的基本上不需要人工干预的搜索引擎。使用这种模式的搜索引擎甚至可以在几天之内就可获取Internet中的所有信息,同时也节省了大量的资金和时间成本。而这种搜索引擎最重要的组成部分之一就是为搜索引擎提供数据源的网络蜘蛛。也就是说,实现网络蜘蛛是实现搜索引擎的第一步,也是最重要的一步。

    二、网络蜘蛛的基本实现思想和实现步骤

        网络蜘蛛的主要作用是从Internet上不停地下载网络资源。它的基本实现思想就是通过一个或多个入口网址来获取更多的URL,然后通过对这些URL所指向的网络资源下载并分析后,再获得这些网络资源中包含的URL,以此类推,直到再没有可下的URL为止。下面是用程序实现网络蜘蛛的具体步骤。

        1. 指定一个(或多个)入口网址(如http://www.comprg.com.cn),并将这个网址加入到下载队列中(这时下载队列中只有一个或多个入口网址)。
        2. 负责下载网络资源的线程从下载队列中取得一个或多个URL,并将这些URL所指向的网络资源下载到本地(在下载之前,一般应该判断一下这个URL是否已经被下载过,如果被下载过,则忽略这个URL)。如果下载队列中没有URL,并且所有的下载线程都处于休眠状态,说明已经下载完了由入口网址所引出的所有网络资源。这时网络蜘蛛会提示下载完成,并停止下载。
        3. 分析这些下载到本地的未分析过的网络资源(一般为html代码),并获得其中的URL(如标签<a>中href属性的值)。
        4. 将第3步获得的URL加入到下载队列中。并重新执行第2步。

    三、实现数据的输入输出

        从实现网络蜘蛛的步骤中我们可以看出,下载队列的读、写URL的操作一直贯穿于整个系统中。虽然这个下载队列可以用.Queue类实现,但是各位读者要清楚地知道,在互联网上的URL可不是几十个、几百个这么少。而是以千万计的。这么多的URL显然不能保存在内存中的Queue对象中。因此,我们需要将它保存在容量更大的存储空间中,这就是硬盘。
        本文采用了一个普通的文本文件来保存需要下载和分析的URL(这个文本文件也就是下载队列)。存储格式是每一行为一个URL。既然将URL都保存在了文本文件中,就需要对这个文本文件进行读写。因此,在本节实现了一个用于操作这个文本文件的FileIO类。
        在实现FileIO类之前,先来说一下要如何操作这个文本文件。既然要将这个文件作为队列使用,那么就需要对这个文件进行追加行和从文件开始部分读取数据操作。让我们首先来实现向文件中追加行操作。实现代码如下:

        向文件中追加行的实现代码
    // 这两个变量为类全局变量
    private FileStream fsw;
    private StreamWriter sw;

    // 创建用于向文件中追加行的文件流和StreamWriter对象
    public void OpenWriteFile(string file)
    {
    if (!File.Exists(file)) // 如果文件不存在,先创建这个文件
    File.Create(file).Close();
    // 以追加模式打开这个文件
    fsw = new FileStream(file, FileMode.Append ,FileAccess.Write, FileShare.ReadWrite);
    // 根据创建的FileStream对象来创建StreamWriter对象
    sw = new StreamWriter(fsw);
    }
    // 关闭写文件流
    public void CloseWriteFile()
    {
    if (fsr != null)
    fsw.Close();
    }
    // 向文件中追加一行字符串
    public void WriteLine(string s)
    {
    sw.WriteLine(s);
    sw.Flush(); // 刷新写入缓冲区,使这一行对于读文件流可见
    }

        在实现上述的代码时要注意,在创建FileStream对象时,必须使用FileShare.ReadWrite,否则这个文件无法被两个或两个以上的Stream打开,也就是说下面要介绍的读文件流将无法操作这个被写文件流打开的文件。从文件中读取行的实现代码如下:

        从文件中读取行的实现代码
    // 这两个变量为类全局变量
    private FileStream fsr;
    private StreamReader sr;

    // 创建用于读取文件行的文件流和StreamWriter对象
    public void OpenReadFile(string file)
    {
    if (!File.Exists(file)) // 如果文件不存在,首先创建这个文件
    File.Create(file).Close();
    fsr = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Read,
    FileShare.ReadWrite);
    sr = new StreamReader(fsr);
    }
    // 关闭读文件流
    public void CloseReadFile()
    {
    if(fsr != null)
    fsr.Close();
    }
    // 从文件中读取一行
    public string ReadLine()
    {
    if(sr.EndOfStream) // 如果文件流指针已经指向文件尾部,返回null
    return null;
    return sr.ReadLine();
    }

        除了上述的读写文件的代码外,FileIO还提供了一个IsEof方法用来判断文件流指针是否位于文件尾部。IsEof方法的实现代码如下如下:

    IsEof方法的实现代码
    // 用于判断文件流指针是否位于文件尾部
    public bool IsEof()
    {
    return sr.EndOfStream;
    }

        FileIO类不仅仅用于对下载队列的读写。在后面我们还会讲到,网络蜘蛛通过多线程下载网络资源时,每一个线程将自己下载的网络资源保存在属于自己的一个目录中。每个这样的目录都有一个index.txt文件,这个文件保存了当前目录的网络资源的URL。向index.txt文件中追加URL也用到了FileIO(index.txt不需要读取,只需要不断地追加行)。


    四、线程类的实现

        要想使网络蜘蛛在有限的硬件环境下尽可能地提高下载速度。最廉价和快捷的方法就是使用多线程。在.net framework2.0中提供了丰富的线程功能。其中的核心线程类是Thread。一般可使用如下的代码创建并运行一个线程:

        在C#中使用线程的演示代码
    private void fun()
    {
    // 线程要执行的代码
    }
    public void testThread()
    {
    Thread thread;
    thread = new Thread(fun); // 创建一个Thread对象,并将fun设为线程运行的方法
    thread.Start(); // 运行一个线程
    }

        虽然上面的代码比较简单地创建并运行了一个线程,但是这段代码看起来仍然不够透明,也就是客户端在调用线程时仍然需要显式地使用Thread类。下面我们来实现一个用于创建线程的MyThread类。C#中的任何类只需要继承这个类,就可以自动变成一个线程类。MyThread类的代码如下:

        MyThread类的实现代码
    // 任何C#类继承MyThread后,就会自动变成一个线程类
    class MyThread
    {
    private Thread thread;
    public MyThread()
    {
    thread = new Thread(run); // 创建Thread对象
    }
    // 用于运行线程代码的方法,MyThread的子类必须覆盖这个方法
    public virtual void run()
    {
    }
    public void start()
    {
    thread.Start(); // 开始运行线程,也就是开始执行run方法
    }
    // 使当前线程休眠millisecondsTimeout毫秒
    public void sleep(int millisecondsTimeout)
    {
    Thread.Sleep(millisecondsTimeout);
    }
    }


        我们可参照如下的代码使用MyThread类:

        测试的ThreadClass类的代码
    class ThreadClass : MyThread
    {
    public override void run()
    {
    // 要执行的线程代码
    }
    }

    // 测试ThreadClass类
    public void testThreadClass()
    {
    ThreadClass tc = new ThreadClass();
    tc.start(); // 开始运行线程,也就是执行run方法
    }

        各位读者可以看看,上面的代码是不是要比直接使用Thread类更方便、直观、易用,还有些面向对象的感觉!

    五、用多线程下载网络资源

        一般来说,网络蜘蛛都是使用多线程来下载网络资源的。至于如何使用多线程来下载,各个版本的网络蜘蛛不尽相同。为了方便和容易理解,本文所讨论的网络蜘蛛采用了每一个线程负责将网络资源下载到一个属于自己的目录中,也就是说,每一个线程对应一个目录。而在当前目录中下载的网络资源达到一定的数目后(如5000),这个线程就会再建立一个新目录,并从0开始计数继续下载网络资源。在本节中将介绍一个用于下载网络资源的线程类DownLoadThread。这个类的主要功能就是从下载队列中获得一定数量的URL,并进行下载和分析。在DownLoadThread类中涉及到很多其他重要的类,这些类将在后面的部分介绍。在这里我们先看一下DownLoadThread类的实现代码。

        DownLoadThread类的代码
    class DownLoadThread : MyThread
    {
    // ParseResource类用于下载和分析网络资源
    private ParseResource pr = new ParseResource();
    private int currentCount = 0; // 当前下载目录中的网页数
    // 用于向每个线程目录中的index.txt中写当前目录的URL
    private FileIO fileIO = new FileIO();
    private string path; // 当前的下载目录(后面带“\")
    private string[] patterns; // 线程不下载符合patterns中的正则表达式的URL
    public bool stop = false; // stop为true,线程退出
    public int threadID; // 当前线程的threadID,用于区分其他的线程

    public DownLoadThread(string[] patterns)
    {
    pr.findUrl += findUrl; // 为findUrl事件赋一个方法
    this.patterns = patterns;
    }
    // 这是一个事件方法,每获得一个URL时发生
    private void findUrl(string url)
    {
    Common.addUrl(url); // 将获得的URL加到下载队列中
    }
    private void openFile() // 打开下载目录中的index.txt文件
    {
    fileIO.CloseWriteFile();
    fileIO.OpenWriteFile(path + Common.indexFile);
    }
    public override void run() // 线程运行方法
    {
    LinkedList<string> urls = new LinkedList<string>();
    path = Common.getDir(); // 获得下载目录
    openFile();
    while (!stop)
    {
    // 当下载队列中没有URL时,进行循环等待
    while (!stop && urls.Count == 0)
    {
    Common.getUrls(urls, 20); // 从下载队列中获得20个url
    if (urls.Count == 0) // 如果未获得url
    {
    // 通知系统当前线程已处于等待状态,
    // 如果所有的线程都处于等待状态,
    // 说明所有的网络资源都被下载完了
    Common.threadWait(threadID);
    sleep(5000); // 当前线程休眠5秒
    }
    }
    StringBuilder sb = new StringBuilder();
    foreach (string url in urls) // 循环对这20个url进行循环下载分析
    {
    if (stop) break;
    // 如果当前下载目录的资源文件数大于等于最大文件数目时,
    // 建立一个新目录,并继续下载
    if (currentCount >= Common.maxCount)
    {
    path = Common.getDir();
    openFile();
    currentCount = 0; // 目录
    }
    // 每个下载资源文件名使用5位的顺序号保存(没有扩展名),
    // 如00001、00002。下面的语句是格式化文件名
    string s = string.Format("{0:D5}", currentCount + 1);
    sb.Remove(0, sb.Length);
    sb.Append(s);
    sb.Append(":");
    sb.Append(url);
    try
    {
    // 下载和分析当前的url
    pr.parse(url, path + s, patterns);
    Common.Count++;
    // 将当前的url写入index.txt
    fileIO.WriteLine(sb.ToString());
    currentCount++;
    }
    catch (Exception e)
    {

    }
    }
    urls.Clear();
    }
    }
    }
    }

    六、分析网络资源

        对下载的网络资源进行分析是网络蜘蛛中最重要的功能之一。这里网络资源主要指的是html代码中<a>标签的href属性值。状态和状态之间会根据从html文件中读入的字符进行切换。下面是状态之间切换的描述。

    状态0:读入'<'字符后切换到状态1,读入其他的字符,状态不变。
    状态1:读入'a'或'A',切换到状态2,读入其他的字符,切换到状态0。
    状态2:读入空格或制表符(\t),切换到状态3,读入其他的字符,切换到状态0。
    状态3:读入'>',成功获得一个<a>,读入其他的字符,状态不变。为了更容易说明问题。在本文给出的网络蜘蛛中只提取了html代码中<a>中的href属性中的url。本文中所采用的分析方法是分步进行提取href。首先将html代码中的<a>标签整个提出来。不包括</a>和前面的字符,如<a href="http://www.comprg.com.cn">comprg</a>中只提取<a href="http://www.comprg.com.cn">,而comprg</a>将被忽略,因为这里并没有url。
    本文使用了一个状态机来的提取<a>,这个状态机分为五个状态(0 至 4)。第一个状态是初始态,最后一个状态为终止态,如果到达最后一个状态,说明已经成功获得了一个<a>

        状态机如图1所示。



    图1

        最后一个双环的状态是最终态。下面让我们来看看获得<a>的实现代码。

    getA方法的实现
    // 获得html中的<a>
    private void getA()
    {
    char[] buffer = new char[1024];
    int state = 0;
    String a = "";

    while (!sr.EndOfStream)
    {
    int n = sr.Read(buffer, 0, buffer.Length);
    for (int i = 0; i < n; i++)
    {
    switch (state)
    {
    case 0: // 状态0
    if (buffer[i] == '<') // 读入的是'<'
    {
    a += buffer[i];
    state = 1; // 切换到状态1
    }
    break;
    case 1: // 状态1
    if (buffer[i] == 'a' || buffer[i] == 'A') // 读入是'a'或'A'
    {
    a += buffer[i];
    state = 2; // 切换到状态2
    }
    else
    {
    a = "";
    state = 0; // 切换到状态0
    }
    break;
    case 2: // 状态2
    if (buffer[i] == ' ' || buffer[i] == '\t') // 读入的是空格或'\t'
    {
    a += buffer[i];
    state = 3;
    }
    else
    {
    a = "";
    state = 0; // 切换到状态0
    }
    break;
    case 3: // 状态3
    if (buffer[i] == '>') // 读入的是'>',已经成功获得一个<a>
    {
    a += buffer[i];
    try
    {
    string url = getUrl(getHref(a)); // 获得<a>中的href属性的值
    if (url != null)
    {
    if (findUrl != null)
    findUrl(url); // 引发发现url的事件

    }
    }
    catch (Exception e)
    {
    }
    state = 0; // 在获得一个<a>后,重新切换到状态0
    }
    else
    a += buffer[i];
    break;
    }
    }
    }
    }

        在getA方法中除了切换到状态0外,其他的状态切换都将已经读入的字符赋给String变量a,如果最后发现变量a中的字符串不可能是<a>后,就将a清空,并切换到状态0后重新读入字符。
    在getA方法中使用了一个重要的方法getHref来从<a>中获得href部分。getHref方法的实现如下:

        getHref方法的实现
    // 从<a>中获得Href
    private String getHref(string a)
    {
    try
    {
    string p = @"href\s*=\s*('[^']*'|""[^""]*""|\S+\s+)"; // 获得Href的正则表达式
    MatchCollection matches = Regex.Matches(a, p,
    RegexOptions.IgnoreCase |
    RegexOptions.ExplicitCapture);

    foreach (Match nextMatch in matches)
    {
    return nextMatch.Value; // 返回href
    }
    return null;
    }
    catch (Exception e)
    {
    throw e;
    }
    }

        在getHref方法中使用了正则表达式从<a>中获得href。在<a>中正确的href属性格式有三种情况,这三种情况的主要区别是url两边的符号,如单引号、双引号或没有符号。这三种情况如下所示:
    情况1: <a href = "http://www.comprg.com.cn" > comprg</a>
    情况2: <a href = 'http://www.comprg.com.cn' > comprg</a>
    情况3: <a href = http://www.comprg.com.cn > comprg</a>
        getHref方法中的p存储了用于过滤这三种情况的href,也就是说,使用正则表达式可以获得上述三种情况的href如下:

    从情况1获得得的href:href = "http://www.comprg.com.cn"
    从情况2获得得的href:href = 'http://www.comprg.com.cn'
    从情况3获得得的href:href = http://www.comprg.com.cn

        在获得上述的href后,需要将url提出来。这个功能由getUrl完成,这个方法的实现代码如下:

    getUrl方法的实现
    // 从href中提取url
    private String getUrl(string href)
    {
    try
    {
    if (href == null) return href;
    int n = href.IndexOf('='); // 查找'='位置
    String s = href.Substring(n + 1);
    int begin = 0, end = 0;
    string sign = "";
    if (s.Contains("\"")) // 第一种情况
    sign = "\"";
    else if (s.Contains("'")) // 第二种情况
    sign = "'";
    else // 第三种情况
    return getFullUrl(s.Trim());
    begin = s.IndexOf(sign);
    end = s.LastIndexOf(sign);

    return getFullUrl(s.Substring(begin + 1, end - begin - 1).Trim());
    }
    catch (Exception e)
    {
    throw e;
    }
    }

        在获得url时有一点应该注意。有的url使用的是相对路径,也就是没有“http://host”部分,但将url保存时需要保存它们的完整路径。这就需要根据相对路径获得它们的完整路径。这个功能由getFullUrl方法完成。这个方法的实现代码如下:

     getFullUrl方法的实现代码
    // 将相对路径变为绝对路径
    private String getFullUrl(string url)
    {
    try
    {
    if (url == null) return url;
    if (processPattern(url)) return null; // 过滤不想下载的url
    // 如果url前有http://或https://,为绝对路径,按原样返回
    if (url.ToLower().StartsWith("http://") || url.ToLower().StartsWith("https://"))
    return url;
    Uri parentUri = new Uri(parentUrl);
    string port = "";
    if (!parentUri.IsDefaultPort)
    port = ":" + parentUri.Port.ToString();
    if (url.StartsWith("/")) // url以"/"开头,直接放在host后面
    return parentUri.Scheme + "://" + parentUri.Host + port + url;
    else // url不以"/"开头,放在url的路径后面
    {
    string s = "";
    s = parentUri.LocalPath.Substring(0, parentUri.LocalPath.LastIndexOf("/"));
    return parentUri.Scheme + "://" + parentUri.Host + port + s + "/" + url;
    }
    }
    catch (Exception e)
    {
    throw e;
    }
    }

        在ParseResource中还提供了一个功能就是通过正则表达式过滤不想下载的url,这个功能将通过processPattern方法完成。实现代码如下:

        processPattern方法的实现代码
    // 如果返回true,表示url符合pattern,否则,不符合模式
    private bool processPattern(string url)
    {
    foreach (string p in patterns)
    {

    if (Regex.IsMatch(url, p, RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture)
    && !p.Equals(""))
    return true;
    }
    return false;
    }
        ParseResource类在分析html代码之前,先将html下载到本地的线程目录中,再通过FileStream打开并读取待分析的数据。ParseResource类其他的实现代码请读者参阅本文提供的源代码。

    七、键树的实现

        在获取Url的过程中,难免重复获得一些Url。这些重复的Url将大大增加网络蜘蛛的下载时间,以及会导致其他的分析工具重复分析同一个html。因此,就需要对过滤出重复的Url,也就是说,要使网络蜘蛛下载的Url都是唯一的。达到这个目的的最简单的方法就是将已经下载过的Url保存到一个集合中,然后在下载新的Url之前,在这个集合中查找这个新的Url是否被下载过,如果下载过,就忽略这个Url。
        这个功能从表面上看非常简单,但由于我们处理的是成千上万的Url,要是将这些Url简单地保存在类似List一样的集合中,不仅会占用大量的内存空间,而且当Url非常多时,如一百万。这时每下载一个Url,就要从这一百万的Url中查找这个待下载的Url是否存在。虽然可以使用某些查找算法(如折半查找)来处理,但当数据量非常大时,任何查找算法的效率都会大打折扣。因此,必须要设计一种新的存储结构来完成这个工作。这个新的数据存储结构需要具有两个特性:

        1. 尽可能地减少存储Url所使用的内存。
        2. 查找Url的速度尽可能地快(最好的可能是查找速度和Url的数量无关)。

        下面先来完成第一个特性。一般一个Url都比较长,如平均每个Url有50个字符。如果有很多Url,每个Url占50个字符,一百万个Url就是会占用50M的存储空间。而我们保存Url的目的只有一个,就是查找某一个Url是否存在。因此,只需要将Url的Hashcode保存起来即可。由于Hashcode为Int类型,因此,Hashcode要比一个Url字符串使用更少的存储空间。
        对于第二个特性,我们可以使用数据结构中的键树来解决。假设有一个数是4532。首先将其转换为字符串。然后每个键树节点有10个(0至9)。这样4532的存储结构如图2所示:



    图2

        从上面的数据结构可以看出,查找一个整数只和这个整数的位数有关,和整数的数量无关。这个键树的实现代码如下:

        KeyTree的实现代码
    class KeyTreeNode // 键树节点的结构
    {
    // 指向包含整数下一个的结点的指针
    public KeyTreeNode[] pointers = new KeyTreeNode[10];
    // 结束位标志,如果为true,表示当前结点为整数的最后一位
    public bool[] endFlag = new bool[10];
    }
    class KeyTree
    {
    private KeyTreeNode rootNode = new KeyTreeNode(); // 根结点
    // 向键树中添加一个无符号整数
    public void add(uint n)
    {
    string s = n.ToString();
    KeyTreeNode tempNode = rootNode;
    int index = 0;
    for (int i = 0; i < s.Length; i++)
    {
    index = int.Parse(s[i].ToString()); // 获得整数每一位的值
    if (i == s.Length - 1) // 在整数的最后一位时,将结束位设为true
    {
    tempNode.endFlag[index] = true;
    break;
    }
    if (tempNode.pointers[index] == null) // 当下一个结点的指针为空时,新建立一个结点对象
    tempNode.pointers[index] = new KeyTreeNode();
    tempNode = tempNode.pointers[index];
    }
    }
    // 判断一个整数是否存在
    public bool exists(uint n)
    {
    string s = n.ToString();
    KeyTreeNode tempNode = rootNode;
    int index = 0;
    for (int i = 0; i < s.Length; i++)
    {
    if (tempNode != null)
    {
    index = int.Parse(s[i].ToString());
    // 当整数的最后一位的结束标志为true时,表示n存在
    if((i == s.Length - 1)&& (tempNode.endFlag[index] == true))
    return true;
    else
    tempNode = tempNode.pointers[index];
    }
    else
    return false;
    }
    return false;
    }
    }

        上面代码中的KeyTreeNode之所以要使用结束标志,而不根据指针是否为空判断某个整数的存在,是因为可能存在长度不相等的整数,如4321和432。如果只使用指针判断。保存4321后,432也会被认为存在。而如果用结束标志后,在值为2的节点的结束标志为false,因此,表明432并不存在。下面的UrlFilter使用了上面的键树来处理Url。

        UrlFilter类的实现代码
    // 用于将url重新组合后再加到键树中
    // 如http://www.comprg.com.cn和http://www.comprg.com.cn/是一样的
    // 因此,它们的hashcode也要求一样
    class UrlFilter
    {
    public static KeyTree urlHashCode = new KeyTree();
    private static object syncUrlHashCode = new object();
    private static string processUrl(string url) // 重新组合Url
    {
    try
    {
    Uri uri = new Uri(url);
    string s = uri.PathAndQuery;
    if(s.Equals("/"))
    s = "";
    return uri.Host + s;
    }
    catch(Exception e)
    {
    throw e;
    }
    }
    private static bool exists(string url) // 判断url是否存在
    {
    try
    {
    lock (syncUrlHashCode)
    {
    url = processUrl(url);
    return urlHashCode.exists((uint)url.GetHashCode());
    }
    }
    catch (Exception e)
    {
    throw e;
    }
    }

    public static bool isOK(string url)
    {
    return !exists(url);
    }
    // 加处理完的Url加到键树中
    public static void addUrl(string url)
    {
    try
    {
    lock (syncUrlHashCode)
    {
    url = processUrl(url);
    urlHashCode.add((uint)url.GetHashCode());
    }
    }
    catch (Exception e)
    {
    throw e;
    }
    }

    }

    八、其他部分的实现

        到现在为止,网络蜘蛛所有核心代码都已经完成了。下面让我们做一个界面来使下载过程可视化。界面如图3所示。



    图3

        这个界面主要通过一个定时器每2秒钟获得个一次网络蜘蛛的下载状态。包括获得的URL数和已经下载的网络资源数。其中这些状态信息都保存在一个Common类的静态变量中。Common类和主界面的代码请读者参阅本文提供的源代码。

    九、结束语

        至此,网络蜘蛛程序已经全部完成了。但在实际应用中,光靠一台机器下载整个的网络资源是远远不够的。这就需要通过多台机器联合下载。然而这就会给我们带来一个难题。就是这些机器需要对已经下载的Url进行同步。读者可以根据本文提供的例子,将其改成分布式的可多机同时下载的网络蜘蛛。这样网络蜘蛛的下载速度将会有一个质的飞跃。



    参考文献:

    1. Programming C#, 4th Edition By Jesse Liberty
    2. Professional C# 2005 byChristian Nagelet al.
    3. Core C# and .NET By Stephen C. Perry
    4. Working with Microsoft Visual Studio 2005 by Craig Skibo, Marc YoungandBrian Johnson
    5. Professional C# 2005 with .NET 3.0 by Christian Nagel, Bill Evjen, Jay Glynn, Morgan SkinnerandKarli

    April 20

    关于这个三国之见龙卸甲

    转贴(部分经个人修改):
    1,这个伟大的影片的伟大的导演李仁港先生,在影片开头的字幕中,赫然写着....原著:李仁港!!!(罗大大,召唤你来自地狱的诅咒.........死者苏生!!!!!!)


    2,撇开赵云投奔刘备时还是个小卒不说,也不说那场夜袭搞得如何,就说之前诸葛大大的出场。首先我提一个问题:诸葛大大是要饭的,还是军师?怎么好像几天没吃东西一样,一出场就顾着吃面条,还要一边吃一边看着那个死人头,还真的挺开胃的!!!(拜托这是军事会议,不是给乞丐派饭)最要命得是吃饱喝足后,说道:“平日不行,但今夜却可以。我算定今夜子时必雷电交加,将有倾盆大雨。”然后感慨的说道:“这个真是天赐良机啊~!”然后拍拍屁股,说句:“此处胜负已定~~”就走了~~(整一个江湖郎中的形象)——到此,我心中诸葛大大温文尔雅,风度翩翩,高深莫测的形象已经被这部影片的编剧先奸后杀,再奸再杀,杀完再奸~~呜呜~~还要自大到自己夸自己(当时我拿着一瓶“美汁源”在喝,一口喷了出来,我的电脑差点为中国的电影事业而献身)


    3,赵云居然为了救罗平安(金宝饰)先和张飞大打出手,关羽先是喊句:“三弟”,让人一看就知道他是去劝架的,谁知一转身就打埋一份,狂汗~~还要刘出来解围(刘备假仁假义,早应该出面制止)还要以身挡枪,如果华仔收枪不及,那就好看咯...话说,当时外面军情十万火急~~~


    4,关张要护送赵云杀开血路去救阿斗,结果刚看到曹军,关说:俺们任务完成了...跑路了....


    5,赵云在曹军中没坚持满3分钟,被打的狼狈不堪,居然抢了曹操的宝剑还不顺手把他干掉....宝剑上写着两字:青缸? 不是.....居然写着:曹操.....(还好可乐瓶没出现)


    6,赵云衣锦还乡...遇到了初恋...皮影艺术家.就这么一面,再想起的时候赵云70多了 (初恋啊 泪奔 -_-!!!) ,这还不算,在人家曹操的辖地(常山),大摇大摆招摇过市,百姓夹道欢迎,还悠哉悠哉的和女友吃烛光晚餐,哇靠!!!这曹操也太厚道了吧


    7,封5虎将的时候马超出来了2秒....猥琐大叔男.....我靠(这就是锦马超?)顺便说下,黄忠的大刀比较象青龙偃月.... 镜头一转,就说挂了——在此,我想颁他们一个奖--“史上最快被秒大奖”


    8,在北伐点将台上,关兴张苞要打架.....诸葛老鬼一脸神秘对赵云说:你就不想留下点美好回忆....喷.... (其他人可以说这句话,但身为蜀国丞相的诸葛亮就不行)


    9,诸葛郎中的锦囊在此充分证明了诸葛亮这个郎中的忽悠,又是青龙白虎两个锦囊,在开战前交给赵云,打开后完全得到反效果,第一个先分裂了赵、关、张(本来兵力就不够还要分兵,分兵不要紧还要赵云去送死),第二个直接把赵、关、张全给废了。狂汗~~~这难道是传说中的锦囊‘秒’计?!!


    10,曹操的孙女就是大手笔啊,拿100匹汗血宝马摆送死"火牛阵"(投石车投就得了)...摆就摆呗,为啥还要韩德骑着去送死呢?(可怜邓芝临死喊着大蜀国万岁...和于荣光大叔的大魏国万岁比嗓门....再次喷... )守城的有连弩不用,冲出去送死。而且那时只有黑火药没有TNT,怎么爆炸效果比美式手雷还强~~~~


    11,最后是曹操孙女,那时候妇女地位低下不可能当官,更不用说做大都督了,就算是曹操孙女也只能沦为政治婚姻的牺牲品,编剧愣是弄了个女都督(可怜赵云一世英名,最后让个小娘们给算计了~~~呜呜~~~赵云大大出来吧!!!活死人的召唤!!!!!!)

    April 19

    爱情是什么[来自TOM Blog]

    这个世界上本没有爱情,动物只有生理上的本能反应,为了物种的延续性而一代代交配下去。人进化了,拥有了精神世界,于是爱情诞生了。最初的爱情只是简单的喜欢而已,经过上千万年的演化,随着精神世界的发展,爱情越来越复杂,逐渐超越了“喜欢”的范畴。现代爱情建立在丰富的交流感知方式和社会信仰上,但仍然脱离不了原始的生理特征。

    爱情是什么,不过是精神上升华了的喜欢而已,不过是他异或她成为了你生命中不可或缺的一部分,两个人的意识交融在一起,然后精神爱情和生理爱情完美的结合起来,再后来,你们告别父母,互相依靠的共渡一生。养育后代本是原始行为,在进化了的精神世界里这被称作“爱情的结晶”。

    爱情是一种奇妙的精神产物。人创造爱情、品尝爱情,有时候却被爱情折磨的死去活来却心甘情愿。爱情又是一种奢侈品,有些人玩不起爱情,硬要把命运和已颓废的爱情捆绑在一起,他们没有名字;有些人生来就有玩弄爱情于股掌之上的资本,但他们不懂爱情,他们叫帅哥或者美女;有些人没有爱情,两个人在沧桑的岁月中,爱情之花还没开放就衍变成亲情,他们有名字但没人知道;更有些人经历或假想了太多不成熟的爱情,他们叫嚷着把爱情展现给世界看,他们是诗人或者精神病患者。

    缘分是一种借口,明明想占有对方,说我们缘分注定在一起;分手了,又说我们缘分已尽;不明真正的原因却归于缘分是一种虚伪,但所有人都愿意被这缘分的表象所覆盖,这就是爱情的可爱之处。

    爱情文学作品是如此的丰富,爱情被宣扬成高度理想化的东西,事实上的爱情却是平淡如水,这就是现实,但很多人不懂,尤其是女人,认为那才是真正的爱情,于是伤害了别人也伤害了自己。

    爱情的最终归宿是亲情,真正的爱情一般来说只能维持十八个月,到了期限两个人的爱情还没有结合成亲情,于是进入爱情疲劳期,主要通过生理上本能的审美疲劳来体现,因为人是动物,最终摆脱不了动物的定义 .
    April 13

    认为自己做不到

    有一匹小马驹,刚生下来不久,就被农夫栓在一个小小的腐朽的木桩上。尽管那个木桩只是浅浅的插在地里而且已经腐朽了,但小马驹凭自己的力量是挣脱不开木桩上缰绳的困绕。到了许多年以后,小马驹长成了一匹千里马,但当农夫牵过缰绳依然把它栓在那个小木桩上的时候,它还是挣脱不开那个已经腐朽透顶的小木桩。只是因为它认为自己做不到。
     
    就好象一块石头,第一种可能是你相信你可以举起来,而第二种可能是你不相信你可以举起来,第一种结果导致也许你在举石头的过程中肩膀脱臼,第二种结果导致你连举都不去举。
    April 09

    这一年,我28岁,也开始回忆了

    感情是让自己更加认识自己,晚间与蓓蓓闲聊时,她如是说

    突然有种冲动,想要将这些年这些事这些人变成文字,写一本给自己看的书
     
    也许置于这时代中,那都只是一些不值一提的小事,于我而言却是一份独一无二的回忆

    在朋友的blog里看到一本书,名字叫《那些忧伤的年轻人》

    整本书里洋溢着对过往的回忆,对80年代校园的憧憬

    书里写到“那一年,高晓松27岁,已经开始回忆了”,作者又何尝不是

    回忆的情绪是可以传染的,于是......

    这一年,我28岁,也开始回忆了......
    April 05

    精诚所至,金石为开

    精诚所至,金石为开

    再一次听到这句貌似很有哲理的话是在午餐前。彼时正无聊地坐在一小礼堂内看着哥们激昂地使着那三寸不烂之舌蛊惑着台下面带或憧憬或迷惘表情的男男女女们去加入那到伟大的直销大潮中...开篇之哲言即在此时从那哥们口中吐出,并附赠古今中外经典案例若干,引得台下掌声阵阵...

    恩...先鄙视一下此君,拿自个都不信的话忽悠人,丫就一骗子...

    从小他就和我一样不信这话,这话的地位和被老师们曲解的爱迪生同学那句经典的汗水与灵感地位相同...都是被踩在地下再跺两脚的东西。丫上学时最大的爱好就是和我一块拿着99分的卷子嗑着瓜子肆意地看着比我们勤奋精诚百倍的好学生们愁眉苦脸纠错时的样子贱笑。呃...很无聊的行为,向那些个同学道下歉先...

    一向认为等到要照着这话去做的时候,通常都是已经到了没招可使,成功几率低下的地步了,只能拿着这话来聊以自慰...按着我这学计算机的说法,就和拿穷算法解MD5密码差不多,抛开效率低下、成本高昂等等不说,能不能算地出来还得看RP,RP实在不够坚挺的说不定有生之年都看不着那结果出来...

    看地通透,却走不穿...时不时地还是会碰到这种那种找不到法子得到却又不肯放弃的境况...于是乎,抱着那么一丝丝的侥幸,走上了精诚所至的路子,至于金石开不开...呃...天知道...

    哎...我非神魔,没有那逆天的实力保障来满足那无穷的欲望;亦非圣人,达不到那无欲无求无悲无喜的境界。我就一凡人,贪、嗔、痴,一样都躲不开避不过!

    想得有点出神,哥们结束课程走来都没注意。猛拍偶肩膀道:“嘿,嘿,回魂了,想啥呢?”

    “呃...我在想午饭是让你请我山珍好呢还是海鲜好!”

    “哪凉快哪呆着去,要做梦回家躺床上挺尸去!”

    “不行不行,今个我就吃定你了,反正我很空,你上哪我就跟到哪,看你受得了多久!”

    “靠,这么无赖......”

    “咱好不容易来听你讲回课,总得学点啥吧,精诚所至,金石为开,咱这会不就是活学活用么...”

    中指一根突兀地树起在偶眼前...
    March 31

    重拾崩碎的信仰,做自己的骑士

     

    小时候,父亲对我的要求很宽松,当许多别的孩子被寄予厚望而送去读那些个兴趣班的时候,父亲只是由着我恣意地玩耍,对我几乎唯一的要求只是“要做个好人”,还是个孩子的我始终似懂非懂,这么简单的事为什么需要这般一次又一次的向我强调?

    父亲说做人要诚实,却看到有人因不愿与人同流做弊被人骂成是傻b,是不团结

    父亲说做人要守信,却看到为蝇头小利而互相攻歼的无耻背叛

    父亲说人要以家庭至上,却看到以追求爱情之名而满嘴慌言的荒诞

    这般的种种却已不是那些来自杂志小报文字,只是三天之内所看到甚至是亲身经历之事......

    曾经所信仰的价值体系正在以肉眼可见的速度在崩溃,被人无情地轻蔑地踩在脚下,悲哀

    固执偏爱那中世纪的骑士们,无论他们的阵营是光明或者黑暗,至少他们有着自己的信仰

    我不愿妥协,我只是想要坚持做那正确的事,我不要随波逐流......我只做自己的骑士

    也许我会一无所有,但没有人可以剥夺我的信仰,谦卑、怜悯、公正、荣誉、牺牲、英勇、诚实...

    其实我对自己的要求很低,就和我父亲对我的期望一样,我只是想要做个好人

     

    “我将我的剑放于神的面前,我以我的生命和灵魂发誓,将水远维护荣誉与正义。我将牢记谏卑、冷悯、公正、荣誉、牺牲、英勇、诚实的美德,用我的一切维护骑士的责任和荣耀。” 我会尽我的努力去遵守以下的守则.

    作为骑士,不管你站在哪一边,黑暗也好,光明也好,都必须遵守的规章,即:荣誉即吾命

    1.英勇无畏:骑士们必须竭尽所能表现出英勇无畏的精神,例如在战场上奋力杀戮或替乡人主张正义,而非强化个人主义的独特性

    2.正义公平:骑士们必须永保中立,不受个人偏私影响.正义和公平就像一把锐刃,必须谨慎持用,并以人道和慈悲约束

    3.忠贞不二:骑士必须对自己所选择的主人及理想忠贞不二

    4.防御保护:骑士们必须允诺竭诚保护主人,人民,家园,以及所有其他骑士可以无怨尤为其付出忠诚的人

    5.胆量勇气:骑士必须挑战艰难的考验,比一般人更能忍受险境,骑士要有为值得敬重的人牺牲生命的准备,他们也必须分辨愚勇和英勇只是一字之差:但记住不要逞匹夫之勇,否则可能以悲剧收场.

    6.坚定的信念:骑士必须对他所信仰的理念坚持不移,如此一来才可以在遇到险境困苦时不致轻言放弃.

    7.谦卑为怀:骑士必须谦卑,不彰显功名,因所有的功成名就绝非个人之力可以完成,称赞其他骑士的正直善行,同时可达宣扬骑士精神之效.

    8.慷慨大方:骑士必须在能力范围里表现他们的慷慨大方,适当的分享给予才不会造成浪费,也有助于正义伸张.

    9.高贵情操:骑士必须时时保持高贵人格,即使梦想无法实现,但在努力的过程就是磨练,就是灵魂向上扬升

    爱情与幸福

     

    单恋

      落花有意,可惜流水无情!单恋,即所谓的“单相思”,更是折磨人,伤害人。
      对于你所爱的人,因为她不爱你,所以你只能远远地欣赏她的倩影。心中即便有万千爱的宣言,也只能埋藏在内心深处,苦苦地压抑。越是痴痴地爱,越是深深地痛!

      记得《明知道相思苦》的一句歌词:认识你之前,是无靠无依,认识你后无药可医!其实,还有一种药可以治好“相思病”—对方的爱!心病还得心药医,解铃还须系铃人也。

      只可惜,既然是“单恋”,那就是说,此病的解药是永远也得不到的,也算是“无药可医”吧!只能让时间流逝,将伤痛慢慢地带走……

    相思

      花自飘零,水自流。一种相思,两处闲愁,此情无计可消除,才下眉头,却上心头!

      这时所说的“相思”,是两情相悦的思念,在惆怅中往往带着一丝甜蜜和幸福。因为这是对恋人的思念,你的恋人也可能在遥远的另一个地方与你共鸣。

      但是,这种相思之苦比单恋来得更加深沉,更加难熬,更加无法自拔。一日不见,如隔三秋!即使心里竭力不去想她,梦里还是会梦到她,醒来之后,发现一切依旧,只会更相思。

      相思之人,往往茶饭不思,夜不能寐,一段时间一来,脸色愈加憔悴,人也逐渐消瘦。于是有词云:衣带渐宽终不悔,为伊消得人憔悴!

     

    被爱

      当一个人爱你爱得发疯,而你对其没有半点感觉的时候,也许你会感受到一丝被爱的虚荣,但更多的,是一种烦恼,一种愧疚。
      爱你的人,总是会出现在你出现的地方,或许他(她)会称其为“缘份”,但天晓得所谓的“缘份”是不是其故意安排。爱你的人,有时就像打探明星隐私的“狗仔队”,让你避无可避,烦恼透顶。而且,他(她)总是会公然地,或者默默地帮你的忙,为你打点周围的琐事。爱你的人称其为“爱的付出”,然而,这实质上是一种投资,一种感情的投资。有付出,也必然渴望得到爱的回报。就是因为明白这一点,对于被爱的人来说,得到对方的帮助越多,心里的愧疚感就越重,好比借了别人一大笔钱而无力偿还一样。
      拒绝对方,是对别人的一种伤害;接受对方,是对自己的残忍!无论你作任何一种选择,总得面对伤痛。

     

    猜疑

      恋人之间,也许彼此太在乎对方,常常会害怕对方的移情别恋,恨不能用一个永远也打不开的保险柜把对方的爱锁起来,免得让它与外边的空气接触而发生变质。

      因此,情人不仅是情人,还是“神探福尔摩斯”:对方一有任何出轨的迹象,一定会暗暗留心,或者当面质问。怪不得现在的爱情类书籍中,都有这样一条“忠告”:在女朋友或者妻子面前,切不可称赞其他的女人;在男朋友或者是丈夫面前,切不可赞扬其他的男人!

      所以即使两个人在一起,还是不能畅情惬意,得留出一份心思来观察对方的动静,还得担心对方会不会禁受不住外界的诱惑而变心,尤其是对方因为工作原因而跟其他异性交触较多时,更是充满了危机感。

      要想享受爱情的幸福,就必须回避这些爱情的痛苦。因此,真正幸福的爱情应该是:两情相悦,两人厮守,彼此信任

    March 26

    愚人节快到了!

    马上就是愚人节了,兄弟姐妹们都打算怎么过啊?别告诉我你又准备往师弟的夹心饼干里抹牙膏,或者往死党的咖啡里掺鞋油。跟亲朋好友下家伙算什么本事啊,这回我们去“娱乐”陌生人! 

    第一招 食色性也——草地里的音“浪”

    想想看,一对情侣光天化日之下在草地里“嘿咻”,声音一“浪”高过一“浪”,伴随着草丛也在索索发抖。路人撞到了,会是怎样的一副表情呢?尴尬、兴奋、惊讶、色迷迷……来试验吧,当然用不着你出卖色相,只需要准备下述材料:

    接线板、有源音箱、装有你看A片时截下声音片断的mp3

    然后找到一片路旁的芳草地。好了,把mp3接到音箱上,连通电源,伪装好后按下PLAY,你就可以钻到草丛里伴随着节奏去摇晃稻草、树枝了。

    路人会是一副什么样的表情呢?


    愚人指数:★★★

    操作指数:★★★★★





    第二招 障眼大法——教室门上的墙

    愚人节是个开心狂欢的节日,但总有憨憨的师弟师妹们照样去教室里努力学习。给他们设置一道障眼的墙吧,看看他们的学习积极性到底有多高。想象一下,熟悉得不能再熟悉的教室,一拉开门,赫然一堵严严实实的高墙。OH,My god!教室被砌死了……

    马上动手准备:去建材城买那种砖墙图案的壁纸,越逼真越好,大小以覆盖住整个教室门为宜。接下来就像挂门帘一样把它朝外挂在教室门上。

    想知道“大跌眼镜”的现场写真什么样子吗?

    愚人指数:★★★★

    操作指数:★★★★





    第三招 出奇制胜——纸箱里的猩猩

    想吓唬人吗?当你好好走在路上的时候,突然从路边的纸箱里跳出一只大猩猩向你呲牙咧嘴,这是件多么恐怖的事情啊。用这招去吓唬路人……

    准备一只足够把你装下的大纸箱,然后是大猩猩面具、黑色紧身衣、毛茸茸的手套。把自己化装成大猩猩,然后躲到纸箱里。当有人从旁边经过时,你就蹭的跳起,大喊大叫,接下来就自己看好戏吧。

    愚人指数:★★★★★

    操作指数:★★★





    第四招 瞒天过海——隐形的绳子

    一条并不存在的绳子能够“绊倒”多少人呢?想起一句话:世界上本来没有路,但走的人多了就形成了路。人的心理或许也是如此吧。这是一个超级简单却又屡试不爽的整蛊试验。

    不用任何道具,拉上你的死党直奔天桥。没错,就是方便行人过马路的过街天桥。你俩一人一边,蹲在天桥的两边,用手比划出拉线的样子。然后所有的行人经过你们这条并不存在的线时,都会不自觉地抬高脚迈过去,有的还要左顾右盼的看上半天。哇,交通拥挤了。

    愚人指数:★★★★★

    操作指数:★★★★★





    第五招 见钱眼开——一元硬币

    ——在地上看到钱了怎么办?

    ——废话,捡阿!

    ——废话!要能捡的起来,早捡起来揣在兜里了。

    捡不起来的硬币?没错,找个硬币,用强力胶粘在地上,看你怎么捡?喂,那位大妈,谁让你拿刀子铲了?……看看人们在金钱面前的种种丑态吧。

    愚人指数:★★★★

    操作指数:★★★★★
    March 22

    Resident Evil 历史表

    二十世纪九十年代前:

      20世纪50年代:亚西福德家族第六代继承人爱德华·亚西福德和斯宾塞在对古生物研究的时候从女王蚁的基因中发现了一种古代病毒。病毒的威力让他们两人感到震惊,这是一种能使生物基因发生变异,丧失思想意识。聪明的两人立即意识到这种病毒用到军事上的巨大用途,并且命名为始祖病毒!

      1960年:亚历山大在美国拿到生物博士学位以后全心投入了病毒的研究。

      1963年:斯宾塞以未来公司主管的权利,聘请了当时著名的设计师乔治·特雷沃在浣熊市郊区的阿克雷山区修建了洋馆(也就是生化1的发生地点)特雷沃家族也开始了他们悲惨的命运。

      1967:S.T.A.R.S在美国成立。同年秋天洋馆的修建完成。知道洋馆机关的只有斯宾塞和特雷沃知道,可怜的特雷沃并没有注意到死亡正逼近自己。

      1967.11.10:女性实验体(莉沙)和母亲(杰西卡)被骗入洋馆内,并被植入病毒母体。

      同年11.14:女性实验体复活,身体不断的异变。

      同月次日:11.15:莉沙在和母亲进餐的时候失去理智,把母亲的脸撕下来贴在了自己的恋上,莉沙认为那并不是自己的母亲。

      同月11.18:特雷沃开始担心家人,但是找不到电话,同时他发现洋馆的一些设施和自己设计的并不一样。

      同月11.21:特雷沃打算离开洋馆,但是无法逃离并且遭到了软禁。在被挟持的途中经过一个由生到死的画的画廊。

      同月11.27:在偶然的情况下他逃离了房间,但是却无法逃出洋馆。他无法解开洋馆的开关,他开始绝望。

      同月11.30:特雷沃的身体越来越差,并且出现了脱水的情况。

      同年12.7:在极度脱水的情况下,他发现了秘道的尽头有写着他名字的墓碑,之后愤然死去。

      1968年:马科斯博士以及斯宾塞,亚历山大正式创立了安布雷拉。制药公司用来演示他们肮脏的行为。

      1971年:由于亚历山大找不到能稳定病毒的办法,疏忽了对公司的打理,斯宾塞在这个时候篡夺了公司的行政大权。

      1974年:威力重振家族的雄风,亚历山大转向遗传基因的实验。但是遭到失败,他认识到自己的智慧有限,他提取了创始人维罗尼卡的基因,通过人工受精的方式创造出了广大玩家熟悉的阿尔福德和阿莱西亚。

      1977年:在干部养成所,新的病毒的研究终于有了结果,在将病毒和DNA的结合中,达到了马科斯博士所期望的突破,而这种病毒就是直接导致浣熊市灭亡的“T病毒”。马科斯决定放弃动物作为实验对象转而换成人类。

      同年:6.3马科斯在实验室被才出道的威斯卡和威廉干掉,但是他的尸体并没有被处理掉而是被投入到了水池中并且冲入了下水道,令人吃惊的是水蛭女王的病毒救了他,并且在十年后重新复活。

      同年11.15:马科斯博士感觉到暗中有人监视自己的实验.1.31.实验室遭到了破坏。为了对抗斯宾塞马科斯决定在董事会上以T病毒相威胁,但是他没有意识到这更加快了他的死亡。

      1978:年轻的威斯卡和威廉来到阿克雷实验室领导T病毒的开发工作,以及对女性实验体的研究。

      1981.10:岁的阿莉西亚从大学毕业后来到安布雷拉工作,凭着自己过人的头脑当上了主任研究员。并且成功开发出了T-Veronica病毒。

      1983年:两兄妹把病毒植入父亲亚历山大体内。经过几周的观察亚历山大被确定为失败的实验品。之后被运往南极基地下牢房。

      12.31年:阿莉西亚将病毒植入自己的体内并且把自己冷冻起来开始了长眠。阿雷福德出任洛克福德岛总司令。不久出现恋妹情节,并且出现人格分裂的状况。这时候的威斯卡也对斯宾塞的目的感到疑惑,脱离组织的想法开始出现。

      1988年:迈克儿·沃伦当上了浣熊市的市长。在他的领导下,很多市民都成为了安布雷拉的职员。危机的前兆拉开了。

    二十世纪九十年代后:

          1995年:警察局长赖恩·艾隆斯开始接受安布雷拉的贿赂,帮助他们掩盖生物实验的真像。还帮助安布雷拉绑架许多市民用于实验。

          同年3.3:威斯卡回到洋馆帮助威廉销毁女性实验体,他怀疑从芝加哥转来的领导人约翰走漏的消息。与此同时,他发现斯宾塞也不再来洋馆,经过3天的生命停止反应后,女性实验体被运往森林的小屋中,那里也存放着她母亲的棺材。

      1996年:陷入经济危机的S.T.A.R.S在安布雷拉的资助下度过了危机,开始了招募新队员。威斯卡在此时争取到了安布雷拉要派人在警署的机会进入了S.T.A.R.S并且担任队长。

      1998年:巴瑞辞去以前的工作来到浣熊市,在警署内帮助威斯卡招募新队员。

      1998年:艾隆斯的秘书开始怀疑他那些名贵的宝物的来处。

      同年5月:马科斯博士在漫长的沉睡中复活,并且以雌雄同体的水蛭人出现,他利用体内的病毒开始向安布雷拉报复。
      同年5月11:马科斯破坏了阿克雷研究所,干部养成所,地下处理场出现感染。不久以后这些设施的人员相继被感染,事态逐渐扩大!T病毒也在洋馆蔓延………

      同年5月20:阿克雷山区发现第一例生化怪物攻击杀人事件,人们在浣熊市的Marbie河的河床上发现一位女性残缺不全的尸体……危机开始爆发。

      同年6月8:艾隆斯开始对秘书凶暴起来,秘书对自己的安全感到担心。同时,新任研究所领导人约翰写了一封决别信给自己的女友ADA,希望她将真相报道给媒体。并希望如果自己变成丧尸她能亲手杀死自己。

      同年6月15:秘书终于发现了局长的秘密,她确定她处于危险之中,日记不连贯的结束了。

      同年6月30:瑞贝卡进入Bravo小队。

      同年7月9: 阿克雷山区发生了数起攻击时间后被R·P·D封锁,S.T.A.R.S被指示去寻找失踪的游客。副队长恩里克作为这次行动的指挥官率领Bravo小组向阿克雷山区进发。

      同年7月21:安布雷拉命令威斯卡完成一些特殊任务:引诱S.T.A.R.S到洋馆和生化武器战斗,除了Tyrant以为的每种生化武器胚胎2个,任务完成后摧毁研究所。同时海军队员比利-科恩被判死刑由阿克雷转到莱克森执行。
     
    同年7月下旬:马科斯向威斯卡等复仇,他指挥水蛭袭击了安布雷拉经过阿克雷的列车。两小时后BRAVO小组来到事发地点并且开始寻找生还者。瑞贝卡和比利在列车中相遇了开始了逃亡之路.
    7.24 马科斯被瑞贝卡和比利消灭,然后比利离开浣熊市,瑞贝卡前往洋馆。Bravo小组与警局失去联系24小时后由威斯卡率领的Alpha小组出发了。刚下直升机就受到了攻击,佛斯特阵亡。众人为了躲避怪物进入洋馆,同时女性实验体开始苏醒。

      同年7月25:事情的真相由S.T.A.R.S的手披露出来。研究所的生化武器被全部消灭。而S.T.A.R.S只幸存了克里斯 吉儿 巴瑞 布拉特 瑞贝卡。威斯卡暴露叛徒身份行踪不明。另一方面威廉顺利的当上主任研究员,并且继续向艾隆斯贿赂。为的是保住自己研究G病毒的事实。

      同年8月中旬:浣熊市区出现疑似T病毒的病痪,不少人目击到丧尸的出现。克里斯想联邦调查局就浣熊市的状况提交了报告,希望进行调查。

      同年8月24:克里斯和FBI的合作,被安布雷拉察觉,也知道了G病毒的存在。克里斯为了更加深入调查G病毒前往欧洲。巴瑞安置好家人以后也前往和克里斯会合。而吉儿留在市内继续调查。

      同年9月中旬:为里夺取G病毒,HCF的间谍ADA潜入浣熊市。

      同年9月23:因为威廉不肯交出G病毒,总部派出特殊部队前往抢夺。在这场争夺战中,威廉重伤,在生命垂危之际向自己身体内注射了G病毒,从而变为G。变异为G的威廉杀死了三名特工,一名特工汉克昏迷。不久后,浣熊市区内发生大量T病毒感染病例。生化危机故事全面爆发!!!

      同年9月26:浣熊市警察局虽然投入大量警力,但是依然敌不过丧尸,十多分钟后全面崩溃。为了回收T病毒治疗和B·O·W安布雷拉投入UBCS进行战斗,但是以后以失败告终。美国上议院也知道G病毒的存在,从而美军开始行动。另外艾隆斯和安布雷拉的交易破裂,气急败坏的他破坏了逃出通路,分散了武器,是救援行动大大延误。
     
      同年9月2:吉儿(JILL)开始了逃亡行动,期间遇到了UBCS的成员卡洛斯、米歇儿、尼古拉。此时安布雷拉将Nemesis投入到市区想歼灭S.A.T.R.S。得知消息的巴瑞也重返浣熊市营救吉儿。

      同年9月22:新任警官里昂来到浣熊市,上任的第一天就遇到了T病毒的事件。此时克里斯的妹妹为了寻找哥哥也来到了浣熊市并与里昂相遇开始逃亡。

      同年9月30:为了寻找最好的遗传体,威廉不断的袭击保护雪莉的里昂和克莱儿。艾窿斯和安耐特也死在他的手上。依靠里昂和克莱儿优秀的能力最终消灭了G。原本以为死亡的ADA也被秘密潜入的威斯卡救活。在里昂和ADA24小时短暂的爱情中承受了太多太多。G病毒也被汉克成功的回收,事件结束后,克莱儿为里寻找哥哥前往欧洲。

      同年10月1:吉儿和卡洛斯一同逃离了浣熊市。

      同时美国政府在得到G病毒后,为了杜绝后患用核弹摧毁了浣熊市,死亡人数超过10万人。

      同年12月12日:为了寻找克里斯克莱儿潜入安布雷拉巴黎分部并被逮捕。

      同年12月22日:克莱儿被送到洛克福德岛。

      神秘组织HCF为了得到始祖病毒样本派威斯卡袭击了洛克福德造成了病毒的泄露。克莱儿成功逃出监狱并与史缔夫相遇。之后她通过网络摆脱里昂向克里斯求救。克里斯为了营救克莱儿来到了洛克福德。之后阿尔弗雷德逃往南极基地。

      同年12月22日:克莱儿和史蒂夫也逃出小岛被阿尔弗雷德带到南极基地,不久后阿莉西亚被临死的阿尔弗德从冰冻状态中唤醒。克里斯也来到南极基地,最后史蒂夫被植入始祖病毒死亡。被威斯克带走。最后克里斯兄妹成功逃离。

    二十一世纪后:

          2004年:在上次事件的六年后里,里昂已经成为直属美国总统的特工人员,而这次的任务就是解救被绑架的美国总统的千金。里昂到达指定地点后才发现迎接他的不是友善之辈。难道六年前的一切又要重演!经过重重激战里昂终于找到了阿什莉,并且遇到了研究寄生虫的路易斯。在探知真相的时候里昂和曾经以为生离死别的ADA重遇了,而现在的ADA是直属与威斯克的间谍不能再向里昂表露感情,所以也是冷言相像。原来一切的一切都是塞德勒领导的邪教所研究的病毒所引发的,目的是为了威胁美国总统。最终在ADA的帮助下里昂和阿什莉去除了身体的寄生虫并且消灭了塞德勒,ADA也向六年前那样把枪指向里昂,这次的里昂没有像六年前那样而是把样本交给了ADA,也许是不想重复六年前的那一幕。最终里昂带着阿什莉逃出了小岛。

      “那个女人是谁?”

      “他是我一辈子都无法抹去的伤痕……”
    March 10

    名词解释:爱情

          一种成分目前还不被人类所掌握的依附于人类大脑的一种东西。你可以把爱情理解为金钱,也可以理解为肉体,也可以理解为其他乱七八糟的任何东西,但是绝对不是海枯石烂爱你一万年!

      爱情双方主体:从1到100岁身体健康有独立思考能力的各种各样的男人女人。但是有一点需要注意:在网络爱情中,叫旺财的家伙不一定是个财主而实际上是条狗,叫小强的家伙不一定很强壮而实际上是一只蟑螂。 

      爱情主体双方的关系:除了近亲,人兽以外的任何关系。 

      爱情的开始:他想一辈子拥有她,或者她想一辈子拥有他。 

      爱情的结束:他拥有了她或者她拥有了他,婚礼举行了结婚证也办了但是双方都开始寻思如何把对方一脚踢回石器时代。 

      关于爱情保险:由于爱情的不确定性和巨大的风险性,已知目前的保险公司还没有一家敢于承保爱情保险。 

      爱情的不确定性:你每天都换内裤么?换?那么好,爱情就像你的贴身内裤。 

      爱情的风险性:保险公司,顾名思义就是通过主动承担风险而获取利润的机构。保险公司可谓胆大包天上到飞机火箭下至汽车轮船,甚至连世界贸易组织大楼都敢于承保,但是却不敢对爱情承保,由此可见爱情遇到风险的机会比恐怖分子劫持飞机撞击大楼要多的多。 

      爱情的价值:婚前像个宝,婚后像根草。 

      纯真的爱情:金钱不是万能的。 

      现实的爱情:没有金钱的爱情是万万不能的。 

      结婚:明知山有虎,偏向虎山行的又一生动事例。 

      爱情保证书:又称结婚证,或者干脆叫劳改判决书。 

      爱情的教育意义:你可以拿着结婚证很方便的对你的学生讲解什么叫做上山容易下山难。 

      爱情的社会意义:正因为有了爱情,才让许多失业的小年轻有事可做让他们觉得这个世界这么美好这么伟大有个这么值得让他好好活下去的姑娘而没有去杀人放火。 

      关于爱情的哲学:情人一思考,上帝就发笑。 

      历史名人是这么说的:在恋爱的时候,真理是如此宝贵,以至于我们不得不用谎言去捍卫她! 

      爱因斯坦这样解释爱情:当她或者他作为一个苹果发育成熟的时候,她就会受万有引力的影响而坠入他或者她的怀抱。 

      军事家的爱情宝典其实是一部军事著作--孙子兵法。 

      关于爱情的数学公式有两个:1+1=1,1+1=3。 

      关于爱情的政治:我们要紧密的团结在以丈母娘为核心的亲友团的周围,认真学习恋人同志下达的关于结婚送礼的报告书,坚决落实恋人同志下达的经济指标。 

      文学中的爱情永远是两个极端,中庸的爱情故事不可能让作者赚到足够多的稿费。 

      政府部长把自己的女儿嫁给了总统,然后他就做了副总理,要注意的是:他女儿并不爱总统,是他爱副总理。 
      喜欢上一个人到底要多用多长时间?有人说只要一秒钟就足够了,有人说要花上一辈子。 

      当遇到你爱我到底有多深这样的问题的时候,标准答案是月亮代表我的心。 

      结婚前女人看到男人有很多女人围着她会感觉很自豪,她觉得她的男人很有魅力。 

      结婚后女人看到男人有很多女人围着她会很生气,她觉得她的男人很花心。 

      世界上最虚伪的谎言莫过于对着恋人深情款款的说:我的爱是无私的。然后脸色一变恶狠狠的说:以后再让我看见你和别的男人在一起我饶不了你! 

      世界上最痴情的爱情是:两个人被困绝境,女人为了救男人情愿让男人把自己给吃了,她觉得这样的话她就永远活在她的心里。 

      世界上最不浪漫的爱情是:事实上这个女人并没有活在他的心里,而是变成了一泡大便被拉了出来,而且这个男人对着大便思考他有没有必要为了纪念一个女人而收藏一泡大便。 

      还有一点,关于爱情有个争论:有人说爱是做出来的,只有肚皮摩擦才有爱情火花;有人说爱是心灵碰撞擦出火花而不是做出来的
    February 24

    在ASP.Net中实现flv视频转换

      实际上是利用.Net中的Process对象来实现的。
      string str=@"d:\test.avi d:\test_allen.flv";
      RunFFMpeg(str);
      //运行FFMpeg的视频解码,
      public void RunFFMpeg(string strCmd)
      {
      //创建并启动一个新进程
      Process p = new Process();
      //设置进程启动信息属性StartInfo,这是ProcessStartInfo类,包括了一些属性和方法:
      p.StartInfo.FileName = "ffmpeg.exe"; //程序名
      p.StartInfo.Arguments = " -i " + strCmd; //执行参数
      p.Start();
      }
      
      //运行Cmd.exe执行Dos 命令,并返回执行结果
      public string RunCmd(string command)
      {
      //创建并启动一个对进程
      Process p = new Process();
      
      //Process类有一个StartInfo属性,这是ProcessStartInfo类,包括了一些属性和方法,例如:
      p.StartInfo.FileName = "cmd.exe"; //程序名
      p.StartInfo.Arguments = " /c " + command; //执行参数
      p.StartInfo.UseShellExecute = false; //关闭Shell的使用
      p.StartInfo.RedirectStandardInput = true; //重定向标准输入
      p.StartInfo.RedirectStandardOutput = true; //重定向标准输出
      p.StartInfo.RedirectStandardError = true; //重定向错误输出
      p.StartInfo.CreateNoWindow = true; //设置不显示窗口
      
      p.Start();
      //p.StandardInput.WriteLine(command); //也可以用這種方式輸入要執行的命令
      //p.StandardInput.WriteLine("exit"); //不過要記得加上Exit要不然下一行程式執行的時候會當機
      
      //必须创建可以自动转换完成以后,结束进程的代码
      return p.StandardOutput.ReadToEnd(); //從輸出流取得命令執行結果
      }
      ------------------------------------
      另一种方法: 用MEncoder转换视频文件为Flv
      mencoder转换视频注意事项
      1、下载 mencoder.exe 和 mplayer.exe
      2、将mencoder.exe 所在文件夹,加入环境变量Path里面 ,如C:\mplayer
      3、微软键+R,输入cmd,命令行打入如下语法
      mencoder d:\test.avi -o d:\testflv.flv -of lavf -lavfopts i_certify_that_my_video_stream_does_not_use_b_frames -oac mp3lame -lameopts abr:br=56 -ovc lavc -lavcopts vcodec=flv:vbitrate=100:mbd=2:mv0:trell:v4mv:cbp:last_pred=3:dia=4:cmp=6:vb_strategy=1 -vf scale=512:-3 -ofps 12 -srate 22050
      语法说明:
      mencoder d:\test.avi -o d:\testflv.flv //将D:\test.avi 输出到 d:\testflv.flv, 参数 -o 代表输出路径
      -of lavf //参数 -of :输出文件的格式,flv文件是属于lavf格式
      -lavfopts i_certify_that_my_video_stream_does_not_use_b_frames //lavf格式的参数设置,对于转换flv格式,最好加上这个长句。意思是不用bframes。
      -oac mp3lame //输出音频编码器,这里用的mp3lame
      -lameopts abr:br=56 //是专门针对mp3lame的参数设置,abr:br=56,是设置音频比特率为56
      -ovc lavc //输出视频编码器
      
      //视频编码器的设置:
      -lavcopts
      vcodec=flv: //指定视频编码器为flv
      vbitrate=500: //指定视频比特率为500 ,低品质为150kb/s,中等品质为400kb/s,高品质为700kb/s
      mbd=2: //宏模块选择算法,值为0~2默认为0,值越大转换越缓慢,但在品质和文件大小方面有好处
      mv0: //编译每个宏模块并选择最好的一个,当mbd=0时无效;
      trell: //会稍微增加品质,mbd>0时效果更明显;
      v4mv: //量子化网格搜索,对每88block找到最优化编码
      cbp: //只能和trell一期使用,评估失真的图像块编码;
      last_pred=3: //与上一帧相比的移动数量预测,值为0~99,1~3比较合适,大于3时对品质的提高已经无关紧要,但却会降低速度;
      dia=4: //移动搜索范围,值为-99~6,对于快速转换,-1是个不错的值,如果不是很重视速度,可以考虑2~4;
      cmp=6: //值为1~2000,默认为0,设置用于全象素移动预算的比较函数
      vb_strategy=1 //对动作很大的场景会有帮助,对有些视频,设置vmax_b_frames会有损品质,加上vb_strategy=1会好点。
      //mencoder的参数
      -vf scale=512:-3 //-vf表示视频格式scale是缩放,512:-3表示强制将宽度设置为512,高度写为-3表示保持高宽比,也可以设置为-1或-2,
      -ofps 12 /*输出视频的帧频,一般,用于flash播放的视频帧频高了没有意义,反而会增加视频文件大小,但如果ofps设置的不合适,
      比如源视频帧频不是ofps的整数倍,可能会导致转换后的视频、音频不同步,
      似乎可以将这一参数改为-noskip来解决这一问题;*/
      -srate 22050 //音频采样率一般为22050或44100。
      
      ----------------------------------------------------------
      Mencoder中文参考手册地址
      http://www.mplayerhq.hu/DOCS/HTML/zh_CN/
      ----------------------------------------------------------
      参数说明:
      -srate 32000 : //声音采样率,22050hz
      -af channels=2:2:1:0:1:1 //右声道
      -af channels=2:2:0:0:0:1 //左声道
      -stereo 0 //立体声
      -oac mp3lame : //输出音频使用mp3编码
      -lameopts mode=2:cbr:br=32 : //码率br=32 kbit
      -ovc xvid -xvidencopts bitrate=200 : //以xvid方式编码,码率200kbps (经实验,目前divx比xvid要快,在使用vhq功能时会稍稍影响速度)
      -vf scale=480:-3 -sws 9 : //变换至480像素宽,高度按比例缩放
      "C:\dance.avi" -o "C:\dance.XviD.avi" //源文件地址 -o到 输出文件地址
      2> 2.txt : //编码日志记录地址
      
      --------------------参数选择分析------------------------
      18fps:这是以前通过多次测试得来的,一般电视剧和动画片15fps就够用了。如果场景变换不是很大,13fps就能保证播放流畅。降低fps值可以使压缩速度更快,对于电影,特别是动作片,要保证流畅无马赛克,就要提高fps,最大24就够了
      选择18fps足以应付大部分,性价比高
      音频采样率32KHz:从录音设备的得来的灵感(以下质量说明为比喻,前面的参数时原有的)
      32KHz - 32Kbps - mono比电话音好些
      44KHz - 64Kbps - J-Stereo 收音机质量
      44KHz -128Kbps - J-Stereo 通行的MP3标准质量
      44KHz -192Kbps - Stereo接近CD质量
      经过多次试验(以上是区间范围,自己可以根据需要选择)
      压片最省空间 - 使用32KHz - 32Kbps - mono,可以保证内容;
      质量要求不高 - 可用32KHz - 128Kbps - mono 性价比比较高;
      空间大高质量 - 44KHz -192Kbps - Stereo对大SD卡用户。
      视频采样率bitrate=150:
      80 - 最小空间占用率,质量最差 转换速度稍快 (与最低音频配合,大小可1min=1M)
      122 - 对底配置机器的小卡用户性价比较高(换面变化快回有马赛克)
      150 - 满足底配置机器对画质的基本要求(对非动作片比较完美)
      248 - 大卡用户的经济选择 (质量较好)
      350 - 大卡高配置的机器 (经济的体现机器优势)
      更高- 用户自己试吧
      总的来说,输出文件的大小受视频采样率、音频采样率影响效果显著,画面尺寸、fps值也影响大小。怎样设置参数要看你的个人实际需要与机器配置。
      另外,还有很多不知道的参数,请大家找找看。
      比如:pess2、pess3、动态FPS、屏幕截取、时间区间设置等
      ------------------------------------------------------------------
      关于音量调节:
      carlwang 写道:个人习惯是不用耳机的,天热带着不舒服,所以声音我一向偏大。
      我的经验如果片源是DVDrip,一般在5以上,如果是rmvb一般2就够了,再大就有爆音了。
      -oac mp3lame -lameopts mode=2:cbr:br=64:vol=2 大家来试试看吧
      ------------------------------------------------------------------------
      
      转换结束,会显示
      Pos: 226.8s 297f (100%) 48fps Trem: 0min 5mb a-v:-0.009 [142:56]
      这里边的内容,小括号里应该是转换的进度,中括号里的内容很重要,142表示视频比特率,56表示音频比特率(比特率这个词不知道用的对不对......)
      转换结束,会显示2行文字:
      Video stream: 142.564 kbit/s (17820 B/s) size: 4046677 bytes 227.080 secs 2700 frames
      Audio stream: 56.938 kbit/s (7117 B/s) size: 1616197 bytes 227.082 secs
      这2行信息我想大家都能明白,其中我一直关注的是那个142.564kbit/s,
      用过flash8自带转换工具的应该知道高级设置里有个选项是最大数据速率,
      当选中中等画质的时候,是400kb/s,而低品质也是150kb/s,也就是说,用那句命令转换的视频,其画质都不如品质的,那么,品质怎么样呢?
      看一下命令:
      mencoder "D:\music.wmv" -o "D:\output.flv" -of lavf -oac mp3lame -lameopts abr:br=56 -ovc lavc -lavcopts vcodec=flv:vbitrate=150:mbd=2:mv0:trell:v4mv:cbp:last_pred=3 -srate 22050
      分析:
      -ovc >大概是output video codec的缩写,制定输出视频编码,选用的lavc,什么意思?说是用了libavcodec的编码器;
      -lavcopts >是lavc的options选项设置
      要设置视频编码的参数了!
      codec=flv >说的是用的flv编码器,这个咱不理;
      vbitrate=150 >video bit rate!视频数据速率!就是它了!原来我设的是150啊!
      改成vbitrate=1000,再试试看!
      结果,和前一次一模一样......
      冷静下来,去往上看了一下官方文档,这个参数是最大数据速率,最大嘛,你设多大都一样啊,看来不是靠它来控制品质。
      结论,设置品质有2种途径:
      1、设置-lavcopts,看这样一句命令:
      -lavcopts vcodec=flv:vbitrate=500:mbd=2:mv0:trell:v4mv:cbp:last_pred=3:dia=4:cmp=6:vb_strategy=1
      在-lavcopts里dia=4:cmp=6:vb_strategy=1这3条
      dia越大品质越高,如果需要快速编码,设置为-1,设为4时已经很有利于品质了;
      cmp越大品质越高,默认值0,是最快速的,一般设到3,设为6已经只会细微提高品质了,但速度会慢
      vb_strategy,大概是1或者0,默认值可能为0,我这里设为1,会对编码有帮助,这个参数我自己没有过多推敲,可能并不影响品质......
      2、加-sws选项,看下面的命令:
      -sws 3
      只是加一个3进去,转换后的效果和前面一种方法大致相同,视频数据速率都是422.5kb/s左右,解释一下
      -sws就是用来设置品质的,默认值为2,那么,为什么不用这种简单的方式呢?我个人认为,用前面一种方法有利于找到一个速度和品质的平衡点,毕竟变化的范围比较大。
      个人见解:
      如此视频格式的转换,最好使用客户端转换,转换好了再传到服务端,因此需要做客户端的一个视频上传小软件
    January 30

    70后,80后,90后的区别

    1、
    70后:工作狂基本上都是70后的。
    80后:而我们,拒绝加班!
    90后 :拒绝上班!

    2、
    70后:他们喜欢穿七匹狼或者猛龙牌子的衣服。
    80后: 我们喜欢G-Star之类的。
    90后 :乞丐服,越花越好,越破越好..一个洞时尚,两个洞潮流,三个洞个性...

    3、
    70后:他们唱k的时候只会乱吼──例如2002年的第一场雪,然后就拼命拉着你喝酒,不让你唱。
    80后:Mic霸一般是我们。
    90后 :我们不止会唱,还会跳!

    4、
    70后:他们的话题除了工作就是股票。
    80后:我们的话题更多,有英超、魔兽……
    90后 :QQ等级,QQ秀...

    5、
    70后:他们如果有笔记本
    ,会喜欢到公众场合用。
    80后:我们才不会背那么重的东西在身上。
    90后 :只要苹果
    笔记本,而且不止一台...

    6、
    70后:他们喜欢喝红酒,一般是长城红酒。
    80后:我们要么不喝酒,要么就喝啤酒。
    90后 :韩国果汁,日本汽水...

    7、
    70后:他们无论任何时候,看到有站着的领导,都会马上给领导让座。
    80后:我们崇尚上下级平等。
    90后:天上地下,唯我独尊!

    8、
    70后:他们娶老婆的时候想娶处女。
    80后:我们觉得无所谓,只要相互感情好就可以了。
    90后:结婚需要感情吗?..需要结婚吗?..

    9、
    70后:他们觉得每个日本人、美国人、台湾人都想攻打中国。
    80后:我们喜欢日本的连续剧、台湾的综艺节目、美国的大片。
    90后:我要去日本,因为我是日系MM...

    10、
    70后:他们希望中国用核弹把上面三个国家(地区)都灭了。
    80后:我们希望和平。
    90后:和我无关!打仗衣服会降价吗?那就打呗~~

    11、
    70后:他们对服务员态度恶劣,或者言语上调戏女服务员。
    80后:我们只在点菜和结帐时会跟服务员说话。
    90后:从不和waitress说话,只会背后讨论她的衣服很土...

    12、
    70后:他们有存款。
    80后:我们有负债。
    90后:我们有老爸!

    13、
    70后:他们会把房子买在番禺或者花都,然后每天早上花一个多小时乘车去上班。
    80后:我们喜欢在公司附近租房子,每天骑车或走路去上班,就为了早上多睡一会。
    90后:我们住哪里都可以,只要BF喜欢...

    14、
    70后:他们结交有背景有地位的人。
    80后:我们结交志趣相投的人。
    90后:我们结交满身文身的帅哥!

    15、
    70后:他们周末约客户去吃饭。
    80后:我们周末约同学去踢球。
    90后:一个礼拜7天周末,想做什么做什么!

    16、
    70后:他们喝酒时喜欢跟别人干杯
    80后:我们能喝多少喝多少,喝不下了,怎么也不肯再喝
    90后:我不是随便喝酒的人,我随便喝起酒来不是人~

    17、
    70后:他们的家进门要脱鞋。
    80后:我们家进门不用脱鞋。
    90后:我们上床睡觉都不脱鞋!

    18、
    70后:他们五一、国庆去旅游,然后会在各个景点门口拍下很多V字手势的照片。
    80后:我们五一、国庆在家睡觉,或者约朋友去唱k,去旅游,我们只会拍景色。
    90后:我们天天是五一,国庆....取消五一,么关系...

    19、
    70后:吃饭时,他们喜欢坐在老板旁边
    80后:我们最好别坐在老板旁边,那才无拘无束
    90后 :我是老板!

    20、
    70后:他们跟陌生人在一起的时候喜欢找话题说。
    80后:我们不太搭理陌生人,故意找话题不累么?
    90后:你谁阿,穿这么土,死开~ 帅哥,交个朋友好嘛?~~

    January 28

    大雪封城

    暴雪第三天
     
    院子里的雪堆得快有一尺厚,看来今个是哪都去不了了
     
    雪花飘得看来还有越来越大的趋势
     
    一会去公司转转,么事就回家来发呆了...暴雪成灾...
     
    发呆...胡思乱想...在想你...
    January 26

    关于爱情(转的)

    1不要为了寂寞去恋爱,时间是个魔鬼,天长日久,如果你是个多情的人,即使不爱对方,到时候也会产生感情,到最后你怎么办?
    2.有人说恋爱要找自己喜欢的人,结婚要找喜欢自己的人,都是片面的。恋人不喜 欢自己有什么可恋的?老婆自己不喜欢怎么过一辈子?
    3.真爱一个人,就要尽量让他开心,他开心了你就会开心,那么双方就有激情了。
    4.不要因为自己长相不如对方而放弃追求的打算,长相只是一时的印象,真正决定能否结合主要取决于双方的性格。
    5.恋爱的时间能长尽量长。这最少有两点好处:一,充分,尽可能长的享受恋爱的愉悦,婚姻和恋爱的感觉是很不同的。二,两人相处时间越长,越能检验彼此是否真心,越能看出两人性格是否合得来。这样婚后的感情就会牢固得多。
    6.男人不坏,女人不爱,这坏不是指心肠狠毒,自私无情什么的。而是指油嘴滑舌,花言巧语。一般的好男人以为说情话是油嘴滑舌,轻浮肉麻的表现,所以不愿去做。对别人这样说是不对,可是对自己老婆,就要油嘴滑舌一点。为什么不能做个心好嘴滑的男人呢?
    7.只会读书的女人是一本字典,再好人们也只会在需要的时候去翻看一下,只会扮靓的女人只是一具花瓶,看久了也就那样。服饰美容是做好一个女人的必要条件,不是充要条件。你还需要多看书。这样你会发现生活更加美好。
    8.平平淡淡才是真,没错,可那应该是激情过后的平淡,然后再起激情,再有平淡。激情平淡应呈波浪形交替出现。光有平淡无激情的生活有什么意思?只要你真心 爱他,到死你也会有激情的。
    9.你爱他吗?爱就告诉他,何必把思念之苦藏在心底深处。怕样子,地位,身份不相配?别怕,爱一个人是美好的
    10.老婆和老妈掉进了河里,我先救老妈,因为是老妈给了我生命,我找不到任何理由丢下她不管。老婆如果没救上来,我可以再给她陪葬,在墓里继续我们的爱情。
    11.经常听说男人味女人味,你知道男人味是一种什么味道,女人味又是一种什么味道吗?男人味就是豁达勇敢,女人味就是温柔体贴。
    12.初恋都让人难忘,觉得美好。为什么?不是因为他(她)很漂亮或很帅,也不是因为得不到的就是好的,而是因为人初涉爱河时心里异常纯真,绝无私心杂念,只 知道倾己所有去爱对方。而以后的爱情都没有这么纯洁无瑕了。纯真是人世间最为可贵的东西。我们渴求的就是她。
    13.天长地久有没有?当然有!为什么大多数人不相信有?因为他们没有找到人生。旅途中最适合自己的那一个。也就是冥冥中注定的那一个。为什么找不到?茫茫人海,人生如露,要找到最合适自己的那一个谈何容易?你或许可以在40岁时找到上天注定的那一个,可是你能等到40岁吗?在20多岁时找不到,却不得不结婚,在三四十岁时找到却不得不放弃。这就是人生的悲哀。
    14.快乐不是一个地方,而是一个方向。一个人之所以快乐, 不是因为他拥有的多,而是因为他计较的少!如果爱了,这样散了,也许注定;如果散了,这样算了,别再回忆。
    15.人生就像一块洋葱,一片一片的拨下去,总有一半会让你流泪。前世五百次的回眸,才能换来今生真实的擦肩而过,我愿用十万次的回眸,换取今生与你的一次邂逅。
    16. 爱情是把双刃剑,当我们拿起来的时候,理想的情况是双剑合一,然后驰骋江湖而快意恩仇;但很多时候是自相撕杀而遍体鳞伤。时间是块磨刀石,这把爱情的双刃剑,在这块石头上也许越磨越光,变成经得起珍藏的宝剑,也许越磨越秃,而成为残钢废铁。我们当然不该逃避现实的感情,只是我们对这把爱情剑带来的伤痛可以承受到什么程度呢?在经历了这一切伤痛以后,我们可以带给对方幸福吗?如果可以,那么留下的伤痕是通往幸福生活的路标,如果不可以呢,那将是永远不能愈合的疼痛。爱往往是快乐幸福的代名词,有时却是那般的沉重深刻。爱一个人却不能坦荡地向世人大声说出来,有爱却不能完完全全地释放出来,人生的悲哀莫过于此。有时爱也是一种奢侈品,无论是付出还是得到!
    17. 女人的幸福在于:他真的爱我 ;男人的幸福在于:她值得我爱。
    18.不要因为寂寞而爱错一个人,不然会因为错爱而寂寞一生
    January 22

    在VS2005中创建项目模板来提高开发效率

    通常情况下,我们会在一段时间内,使用同一种开发工具开发结构相近的项目,比如在VS2005中开发Web应用程序,数据访问使用iBATIS.NET。对于Web项目来说,它往往包含了js、css、image等文件夹和相应文件,还有经过配置的Global.asax、web.config文件,此外还有通用的用户管理、日志等内容;使用iBATIS时,则需要包含dao.config、sqlMap.config、providers.config等文件。我们可以在项目开始时将这些文件拷贝过去。这也许不是什么大问题,但毕竟还是不方便。

    项目模板和项模板可给我们带来方便,为我们省却上面的烦恼。

    结构

    首先来看看VS2005中的模板结构。VS2005默认附带了一些项目模板,比如Windows 应用程序,类库,Web Site以及Web Service等。在新建一个Web Site项目时,会出现下面的窗体:

    VS2005会选择下面目录中的模本:

    C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\ProjectTemplates\Web\CSharp\1033

    当然这个路径取决于VS2005的安装路径。

    看看这个文件夹下的文件,会发现每个项目都对应于一个zip文件。zip文件里包含创建项目所需的文件,还包含了一个扩展名为vstemplate的文件,该文件包含了创建项目所需的信息,并以XML的格式存储了项目模板的元数据(Meta data)。

    简单来说,创建模板需要创建vstemplate文件和zip文件包。但是,我们在何处存放zip文件呢?VS2005给了我们很大的自由,我们甚至可以存放在网络驱动器中,这对团队开发会大有裨益。那么如何配置呢?

    1、在VS2005中,打开Tools->Options

    2、展开Projects & Solutions

    3、点击General

    4、修改相应的项目模板或项模板位置,可以是网络启动器

    经过上述配置后,团队中的开发人员可以共享一组项目模板。

    创建项目模板

    创建模板的过程相当简单。

    1、创建一个预定义的模板

    2、进行修改,比如添加页面、类等

    3、保存项目

    4、点击File->Export Template

    5、跟随向导完成创建。

    为演示该过程,我创建了一个名为templatearticle的网站。文件夹结构看起来如下:

    然后点击File->Export Templates,导出模板的向导窗体出现:

    此处可以选择模板类型,模板的源项目,模板项目所用的语言。

    点击Next。

    出现Select Template Options窗体:

    设置模板名称和描述信息。可以选中“自动导入到Visual Studio”。

    点击Finish完成。

    创建项模板过程类似,只需在第一步时将模板类型选择为Item Template。

    使用项目/项模板

    通过上述步骤,我们已经成功创建了项目/项模板。下面来看一下如何使用它们。

    1、通过项目模板创建项目

    • 点击File->New->Web Site.
    • New Web Site会出现

    • 在My Templates中,可以注意到有个名为Template Article的模板。
    • 在输入站点名称后,项目就得以创建。

    从模板创建项

    右击项目文件夹,选择Add New Item

    Add New Item Window出现

    可以看到Registration Class项模板。

    输入名称,项得以创建。

    至此,模板创建和使用的简单介绍就完成了。不过它的详细用法就要你去研究了 :)

    参考:

    Speed Up with Project Templates Using Visual Studio 2005

    本文来自于博客园 作者:Anders Cui

     

    January 18

    无奈,随波逐流还是破而后立?

    VS2008的发布已经近在眼前
     
    更多的新概念新思想新技术......Microsoft的技术更新总是不给我们一丝的喘息时间
     
    是继续跟随MS的脚步坚持.NET的路线还是全面转向开放度更高的其他平台体系?
     
    无奈的难题...
     

    当编程语言不再是最容易的部分

    对于很多已经成为资深的开发人员而言,C# 3.0及其Lambda + LINQ的出现就好像晴朗的天空中从远处飘来的一片乌云。原因是,当我们致力于研究如何应付业务快速变化的同时,语言本身的灵活性却在空前提高,不断的变革。如果您对COM开发中的各种宏和Inline定义还记忆犹新的话,相信您也不会忘记那个时代看起来很“Cool”的与很平凡的代码之间的区别;现在C# 3.0又把这些翻出来,只不过这次变革的动力更多来自于如何在访问数据时动态提取强类型的需求。很多以往我们需要数十行代码完成的函数现在只要一行Lambda表达式就可以了,而且因为它执行的对象可以根据需要切换到不同的数据源,如:XML数据、关系数据库,甚至Google和Amazon的Web服务。因此,是否掌握语法中这些新的特性将很大程度上关乎你团队的开发效率,起码是编码部分的效率,难点在于是否还有心思坐下来重新学习这个“熟悉的陌生人”了。比如:下面一段代码仅仅是对一个一维数组操作的对照测试组:
    public class Test { int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; public IEnumerable TestLambda() { return numbers.TakeWhile((n, index) => n >= index); } public IEnumerable TestOrdinaryRoute() { IList list = new List(); for (int i = 0; i < numbers.Length; i++) { if (numbers[i] >= i) list.Add(numbers[i]); else break; } return list; } }


    当模式和迭代成为我们这个时代开发主旋律的时候,动态语言因为其灵活性快速膨胀至Web开发的方方面面,但动态语言是否有足够的力量的开发我们需要的ERP、CRM等OLTP应用呢?应该可以,不过我不太会用。对于很多用户而言,“能够早点完成工作按时下班就是最好的用户体验”。而Lambda只是一个开始,他刚好位于一个全能的通用语言之中,并令C#本身在可以支持密集计算的同时,又可以根据外部类型的变化、根据外部信息对象的变化,主动地调整自己的计算;并且可以把这些动态变化的能力从业务对象一直传递到最前端的用户界面部分。上面的例子只是对一维数据的操作,但随着业务规则日趋复杂,我们经常面对的是,用关系数据库或XML数据库组织的具有层次关系的数据(比如:用户提单和提单明细间的关系);这时候在操作相对复杂结构对象的时候,Lambda的简洁优势更加明显了。


    当语言的灵活与语法的复杂汇合在一起的时候,我们也许很有必要重新认识哪些是最容易的,哪些需要投入更多时间来琢磨的。语言未必是最容易学习的部分。

    本文来自于InfoQ 王翔译