图文详解:安装Windows 7 Beta到VirtualBox虚拟机

微软发布Windows 7 Beta有一段时间了,试用者的反馈都还不错。我想大多数人都不会直接把自己电脑上的Windows系统升级到Windows 7 Beta版吧,虚拟机技术的发展,为大家试用各种软件提供了便利的手段,特别是操作系统软件。本文便是笔者使用Sun xVM VirtualBox安装Windows 7 Beta版的全程实录。

首先,要下载Windows 7 Beta的安装盘镜像。微软网站已停止提供下载了,不过从网上搜索一下,还是很容易找到的。我便是从网上找到的32位Windows 7 build 7068。

选用VirtualBox作为虚拟机软件,因为它是免费的,可以从http://www.virtualbox.org下载,目前的最新版本是2.1.4。

安装了VirtualBox并启动后,点击工具栏中的New图标创建新的虚拟机。虚拟机的创建过程是向导式的,向导的第一页是欢迎页,按下Next按钮后显示如下界面。

选择操作系统类型

在此界面中指定虚拟机的名称和操作系统类型。可以看到VirtualBox中已经可以指定操作系统类型为Windows 7了。

之后的步骤为虚拟机分配内存和创建虚拟硬盘。笔者为虚拟机配置的是1G内存,40G硬盘。

向导的最后一步是总结,如下图所示:

虚拟机创建总结

向导完成后,在VirutalBox主窗口的左侧列表中选中刚创建的虚拟机,按下Setting图标,对虚拟机各项参数进行设置。

先设置General页,在此页中,我把显存容量设置为64MB并可用3D加速,其他设置项保持不变,如下图所示:

设置显存和3D加速

然后设置CD/DVD-ROM,将其Mount到Windows 7 Beta版的安装盘镜像文件。

设置光驱到镜像文件

其他选项卡保持不变,点击OK按钮完成设置。从VirtualBox主界面按下Start图标启动虚拟机,虚拟机将由Windows 7安装盘启动。

经过一小段时间的启动过程后,虚拟机的屏幕上显示出以下界面:

语言区域选择

保持图中的选择按下Next按钮后,在出现的界面上点击“Install Now”开始安装。安装过程的第一步是选择要安装的版本:

选择安装版本

选择Windows 7 Ultimate后继续。 下一页中勾选接受licencse terms并继续后,出现以下界面:

升级或安装?

选择Custom(advanced)进行全新安装。在下一个窗口中选择要安装到的硬盘后开始安装过程。

WIN7_4

安装过程需等待较长时间,完成此过程后自动重启。重启后进入Windows 7设置界面,首先设置用户名和计算机名。

设置用户名和计算机名

然后设置密码。(可以留空)

WIN7_6

下一步是输入产品密钥。可以暂时留空。

WIN7_7

设置自动更新:

WIN7_8

选择上图第一项采用推荐设置后,进入下一步设置时区,日期,时间。

WIN7_9

选则上图所示的时区后,下一步设置计算机当前位置,选择后系统将自动配置网络环境。

WIN7_10

笔者选择的是Home Network,选择后,系统开始配置网络,等待一段时间后,终于进入了Windows 7桌面。不过右下角小喇叭上有一把红叉,声音驱动未能成功安装。检查后发现,忘记为虚拟机设置声音了。关闭虚拟机后设置声音如下:

设置声音

重新启动虚拟机,声音驱动仍然不能成功安装。通过Windows Updates找到声卡驱动更新。

WIN7_12

更新声卡驱动后声音工作正常。

至此,Windows 7 Beta安装成功,不过需在三十天内激活。激活时需要提供正确的产品密钥(Product Key),可以到 http://www.microsoft.com/windows/windows-7/beta-download.aspx 使用Windows Live ID申请。笔者申请了一个并成功激活。

另通过虚机窗口的Devices -> Install Guest Additions... 可以安装Guest Additions,使虚机的windows 7环境和VirtualBox更好地集成。

最后,放上一张运行在VirutalBox中的Windows 7 Beta全屏截图,正在运行的是陪伴Windows各版本一路走来的“画笔”程序。

WIN7_11

Posted in 电脑网络 | Tagged , , | 4 Comments

使用Perl和正则表达式批量修改文件(三)

通过前两节()的介绍的方法,已经可以通过正则表达式替换完成很多的批量文件修改工作了,不过还有一些限制。看看下面这篇短文(文件名cyj.txt):

重阳节,农历九月初九,二九相重,称为"重九"。汉中叶以后的儒家阴阳观,有六阴
九阳。九是阳数,固重九亦叫"重阳"。民间在该日有登高的风俗,所以重阳节又称"登
高节"。还有重九节、茱萸、菊花节等说法。
唐代诗人沈佺期《九日临渭亭侍宴应制得长字》诗:"魏文颂菊蕊,汉武赐萸囊……,年 年重九庆,日月奉天长"。《旧唐书·王勃传》记载:王勃的《滕王阁序》就是在重阳 节这一天写出来的。当时王勃的父亲担任交趾令,王勃前往探视父亲,九月九日路过 南昌时,洪州牧阎伯屿正在重修的滕王阁中宴请宾客及部属,他想夸耀女婿吴子章 (孟学士)的才气,便事先拿出纸笔请宾客动笔作序,所有的宾客都知道他的用意, 没有人敢作。却不料王勃事先并不知道州牧的用心,于是毫不谦让接过纸笔。州牧原 本心中十分生气,立即派人在旁边看王勃书写,谁知道王勃才气不凡,蓄积已久的心 情完全发泄出来,文章越写越好,当写到"落霞与孤鹜齐飞,秋水共长天一色"的词句 时,忍不住拍案叫绝!王勃从此一举名震诗坛。

文中的双引号都是用的半角的,而且不分左右。如何能把半角的双引号替换为全角并且能正确的使用“”呢?如果熟悉正则表达式的话,应该很容易就能想到使用s/"(.*?)"/\1/g来进行替换。那么,我们尝试以下命令:

Windows环境: perl -p -e "s/\"(.*?)\"/\1/g" cyj.txt

Linux环境: perl -p -e 's/"(.*?)"/\1/g' cyj.txt

上面的命令行中没有指定 -i 参数,所以替换后的结果会直接输出到屏幕上而不是写入文件中,很多时候,我们都需要用这种方法先看看替换结果是否正确。运行后,可以看到屏幕上输出以下替换结果:

重阳节,农历九月初九,二九相重,称为“重九”。汉中叶以后的儒家阴阳观,有六阴
九阳。九是阳数,固重九亦叫“重阳”。民间在该日有登高的风俗,所以重阳节又称"登
高节"。还有重九节、茱萸、菊花节等说法。
唐代诗人沈佺期《九日临渭亭侍宴应制得长字》诗:"魏文颂菊蕊,汉武赐萸囊……,年 年重九庆,日月奉天长"。《旧唐书·王勃传》记载:王勃的《滕王阁序》就是在重阳 节这一天写出来的。当时王勃的父亲担任交趾令,王勃前往探视父亲,九月九日路过 南昌时,洪州牧阎伯屿正在重修的滕王阁中宴请宾客及部属,他想夸耀女婿吴子章 (孟学士)的才气,便事先拿出纸笔请宾客动笔作序,所有的宾客都知道他的用意, 没有人敢作。却不料王勃事先并不知道州牧的用心,于是毫不谦让接过纸笔。州牧原 本心中十分生气,立即派人在旁边看王勃书写,谁知道王勃才气不凡,蓄积已久的心 情完全发泄出来,文章越写越好,当写到“落霞与孤鹜齐飞,秋水共长天一色”的词句 时,忍不住拍案叫绝!王勃从此一举名震诗坛。

仔细观察后发现,有好几处双引号都没有正确替换。第一节中介绍正则表达式参数 g 时提到过,perl –p命令行每次读取文件中的一行进行处理,所以对于跨行的双引号对,上述的命令行就不能正确匹配处理了。

要解决这个问题,需要使用perl的另一个命令行参数 -0 ,它的作用是为perl每次读取文件内容指定一个分隔符,-0 参数后紧跟一个八进制数或十六进制数,若是十六进制数,需要使用前缀x。比如 –040 和 -0x20 都表示使用空格作为分隔符。而 -0 参数有几个特别的用法用得非常广泛,分别是 -0、-00、和 -0777 。单独指定 -0 表示以 null 字符串作为分格符,在处理普通的文本文件时一般用不上它。 -00 表示使用段落模式,也就是每次读取一个段落。-0777 表示一次读取整个文件。上例中的短文,由于不存在跨越段落的双引号对,使用 -00 和 -0777 都是适合的。

不过,就算加上了 -0777 这样的参数,结果确还是和上一条命令一模一样,怎么回事呢?原因是正则表达式s/"(.*?)"/“\1”/g中的句点 . 号不能匹配换行符。使用正则表达式的 s 参数使得句点可以匹配换行符。所以以下命令行可以成功替换短文中所有的双引号:

Windows环境: perl -0777 –p -i.bak -e "s/\"(.*?)\"/\1/gs" cyj.txt

Linux环境: perl –0777 -p -i.bak -e 's/"(.*?)"/\1/gs' cyj.txt

-i.bak 参数前两节中都有说明,这里就不复述了。命令运行后,cyj.txt的内容被修改成如下内容:

重阳节,农历九月初九,二九相重,称为“重九”。汉中叶以后的儒家阴阳观,有六阴
九阳。九是阳数,固重九亦叫“重阳”。民间在该日有登高的风俗,所以重阳节又称“登
高节”。还有重九节、茱萸、菊花节等说法。
唐代诗人沈佺期《九日临渭亭侍宴应制得长字》诗:“魏文颂菊蕊,汉武赐萸囊……,年 年重九庆,日月奉天长”。《旧唐书·王勃传》记载:王勃的《滕王阁序》就是在重阳 节这一天写出来的。当时王勃的父亲担任交趾令,王勃前往探视父亲,九月九日路过 南昌时,洪州牧阎伯屿正在重修的滕王阁中宴请宾客及部属,他想夸耀女婿吴子章 (孟学士)的才气,便事先拿出纸笔请宾客动笔作序,所有的宾客都知道他的用意, 没有人敢作。却不料王勃事先并不知道州牧的用心,于是毫不谦让接过纸笔。州牧原 本心中十分生气,立即派人在旁边看王勃书写,谁知道王勃才气不凡,蓄积已久的心 情完全发泄出来,文章越写越好,当写到“落霞与孤鹜齐飞,秋水共长天一色”的词句 时,忍不住拍案叫绝!王勃从此一举名震诗坛。

最后,再解释一下perl正则表达式的 s 参数和 m 参数。从上例中我们可以看到,s 参数使得句点可以匹配换行符而不带 s 参数则不可以。s 启用了正则表达式的“单行模式”,使的换行符和其他字符一样,可以被句点匹配。 而 m 启用的是多行模式,它影响的不是句点符,而是正则表达式中的另外两个特殊符号 ^$ ,它们分别匹配行首和行尾这两个位置而不是任何字符,不指定 m 参数时,^ 和 $ 分别匹配的是字符串的开始和结尾处,而指定 m 参数后,^ 和 $ 分别匹配每一行的行首和行尾。由于 s 和 m 分别影响不同特殊字符的匹配行为,所以它们可以组合使用,同时指定 s 和 m 参数的结果是句点可以匹配换行符的同时 ^ 和 $ 还能匹配每一行的行首和行尾。

总结:

  1. 使用perl -p -i.bak -e "s/搜索/替换/参数" 文件名 命令行可以对文件名指定的文件进行正则表达式替换处理。源文件备份到相应的.bak文件。
  2. Linux环境下,可直接在文件名中使用通配符指定多个文件。Windows环境下虽然不可以直接在文件名中使用通配符,却也可以通过 FOR 命令达到相同的目的。
  3. 指定政策表达式参数 g 进行全局替换,否则每次替换过程中只会替换匹配到的第一处。(默认情况下,每次替换过程是文件的一行。)
  4. 正则表达式中使用括号()可以进行分组捕获,而使用\1,\2等可以引用捕获到的内容。
  5. perl命令行的 -p 参数实际上等同于一个循环读取文件内容并输出的程序,而 -e 参数后面跟着一个perl语句在每次循环读取文件内容后执行,每次执行后处理过的文件内容被输出。-i 参数使得输出的内容被写回源文件。
  6. s/搜索/替换/参数 还有 s{搜索}{替换}参数 等多种写法,可以避免过多的转义符。
  7. perl的 -0 参数可以指定每次读取文件内容时的分隔符。-00 和 -0777 分别指示perl按段落读取和全文读取。
  8. 正则表达式的 s 参数使得句点 . 可以匹配换行符。而 m 参数使得 ^ 和 $ 可以匹配每行的行首和行尾。这两个参数可以组和使用。
Posted in 电脑网络, 软件开发 | Tagged , | 1 Comment

使用Perl和正则表达式批量修改文件(二)

上一节中介绍了用perl命令行结合正则表达式批量修改文件的基本方法,基本的命令行模式如下:

perl -p -i.bak -e "s/搜索/替换/参数" 文件名

本节先解释一下各个参数的意义。

-e 使perl可以在命令行直接运行一小段语句,-e 后面跟着的就是要执行的语句内容,比如:

perl -e "print 1+2;"

执行后会输出3。

在介绍-p参数之前,先介绍一下-n。-n 参数形成了一个循环,使得通过命令行可以逐行处理指定的文件。比如:

Windows环境: perl -n -e "print \"$.: $_\"" file1

注:在Windows环境下,如果由双引号括起来的命令行参数中出现双引号时,可以用反斜杠转义。

Linux环境: perl -n -e 'print "$.: $_"' file1

注:在Linux环境下,命令行参数既可以用双引号也可以用单引号来包含,需要转义时也可以用反斜杠“\”。但是,要特别注意的是,如果是双引号的话,其中的“$name”形式的内容会被相应的环境变量的值替换,所以建议默认采用单引号。

等价于以下perl程序:

LINE:
  while (<&gt ;)  {
    print "$.: $_"
  }

也就是会把指定文件的内容每行的前面加个行号之后输出。(<>打开命令行参数中文件名制定的文件,一行行读取,每一行的内容保存在perl的缺省变量$_中,而$.也是perl的一个特殊变量,表示当前的行号。)

-p 在 -n 的基础上,确保缺省参数的值会被输出,比如:

Windows环境: perl -p -e "$_ = \"$.: $_\"" file1

Linux环境: perl -p -e '$_ = "$.: $_"' file1

等价于以下perl程序:

LINE:
  while (<&gt ;)  {
    $_ = "$.: $_"
  } continue {
    print or die "-p destination: $!\n";
  }

作用和之前用-n参数的例子相同。

-i 参数表示原位编辑(inplace edit),输出的结果直接写回到原始文件中,-i.bak可以创建原文件的备份,当然,也可以使用-i.old等来为备份文件指定别的扩展名。(其实,perl解释器在读取文件之前先将原文件更名为对应备份文件名,再创建以原文件名为名的新文件接收输出结果。)

解释了以上参数以后,再来理解以下用来做正则表达式批量替换的命令行就容易了:

perl -p -i.bak -e "s/搜索/替换/参数" 文件名

在perl中,作为一个单一语句,“s/搜索/替换/参数 ”等价于 “$_ =~ s/搜索/替换/参数”,对缺省参数进行正则表达式替换运算。-p -i.bak的组合使得perl解释器一行一行循环读取命令行参数指定的文件,进行正则表达式替换运算后输出,输出结果写入原文件名指定的文件中,原文件备份到对应的.bak文件中。

做为本节的结束,我列出了几个小例子,供大家参考:

perl -p -i.bak -e "s/(\d\d)\/(\d\d)\/(\d{4})/\3-\1-\2/g" filename

将filename指定文件中的mm/dd/yyyy格式的日期转换为yyyy-mm-dd格式。比如:10/31/2008将被转换为2008-10-31。分别捕获月日年后调换顺序并使用“-”进行拼装。

perl -p -i.bak -e "s/ +$//" filename

将filename指定文件中的每一行的行尾空格清除。由于每一行只可能匹配一次行尾空格,所以正则表达式中不需要参数g。

perl -p -i.bak -e "s/\b(colo)u(r)\b/\1\2/gi" filename

将filename指定文件中的所有英式写法的colour改成美式写法的color,不区分大小写(由正则表达式的i参数声明),而且保持原有的大小写。将原有的colo和r分别捕获后再拼装回来。

perl -p -i.bak -e "s/(?<=\bcolo)u(?=r\b)//gi" filename

和上例的作用相同,不过采用了零宽断言,整个正则表达式仅匹配了u一个字母后将其替换为空。

perl -p -i.bak -e "s{catch\s*\(\s*(?:System\.)?Exception\b.*\K$}{ //TODO: 检查异常处理}g" program.cs

上面的这个例子可以找到C#程序文件program.cs中所有直接捕获Exception类型异常的语句并在当行结尾处添加一个TODO注释。(程序员在写异常处理代码时,应该尽可能捕获特定的异常进行处理。一般情况下,不应捕获所有异常进行处理。)此例中有几个值得注意的地方。首先是正则表达式的格式不是之前一直在用的“s/搜索/替换/参数”,而是“s{搜索}{替换}参数”,这样在正则表达式有很多“/”时避免过多的转义符,perl还支持多种不同的格式来书写正则表达式,有兴趣的话可以查看相关资料。再注意一下“\K”,它表示在它之前的所有内容都不成为匹配结果的一部分,类似于它之前的部分都成为了回顾零宽断言。

下一节,将结合更复杂的示例介绍进一步介绍使用Perl和正则表达式批量修改文件的方法,将会引入新的Perl命令行参数。

Posted in 电脑网络, 软件开发 | Tagged , | 2 Comments

使用Perl和正则表达式批量修改文件(一)

由于各种原因,程序员们经常要对多个源代码文件进行有规则的批量修改,大多数情况下,这种修改都是手工完成的。手工进行这种批量修改,费时费力而且还枯燥无味。既然是有规则的修改,是不是可以自动完成呢?

如果是对固定字符串的替换,使用大部分编辑器和集成开发环境提供的“搜索并替换”功能就可以完成任务了。如果对变量,方法,类等进行改名操作,一些集成开发环境(如Visual Studio 2005/2008,Eclipse等)提供的重构功能可以安全地达到目的。而遇到复杂一点的情形,用上述的方法就行不通了。

本文要介绍的方法是结合正则表达式的强大搜索替换能力和Perl便利的文本处理能力来进行比较复杂规则的批量文件修改。使用这种方法,不需要学习Perl语言,因为只需要用Perl命令行就够了,当然如果懂Perl的话更好。虽然不用学习Perl,但正则表达式却是必须会用的,本文就不详细介绍正则表达式了,网上可以找到很好的教程。

从一个简单的例子开始,先看一段C#代码:

using System;
using System.Collections.Generic;
namespace MyTest { public class TestNullable { public string Name { get; private set; }
public Nullable<DateTime> Birthday { get; set; }
public Nullable<int> Age { get { Nullable<int> age = null;
if (Birthday != null) { age = DateTime.Now.Year - Birthday.Value.Year; } return age; } }
public Nullable<bool> Sex { get; set; }
public IDictionary<Nullable<Guid>, Nullable<int>> Records { get; private set; }
public TestNullable(string name) { Name = name; Records = new Dictionary<Nullable<Guid>, Nullable<int>>(); } } }

这段代码中的,Nullable数据类型都是用“Nullable<值类型>”的形式声明的。如果有一天,上司要求统一规范,所有的Nullable数据类型都必须以值类型后跟一个“?”号的形式来声明,比如“Nullable<int>”改为“int?”,怎么办呢?别急,只用如下一条简单的命令行就可以完成转换了:

perl –p -i.bak -e "s/Nullable<(\w+)>/\1?/g" TestNullable.cs

转换结果如下:

using System;
using System.Collections.Generic;
namespace MyTest { public class TestNullable { public string Name { get; private set; }
public DateTime? Birthday { get; set; }
public int? Age { get { int? age = null;
if (Birthday != null) { age = DateTime.Now.Year - Birthday.Value.Year; } return age; } }
public bool? Sex { get; set; }
public IDictionary<Guid?, int?> Records { get; private set; }
public TestNullable(string name) { Name = name; Records = new Dictionary<Guid?, int?>(); } } }

酷吧,再看一下这个神奇的命令:

perl –p -i.bak -e "s/Nullable<(\w+)>/\1?/g" TestNullable.cs

perl是Perl语言的解释器,一般Linux操作系统下都是默认安装的,Windows系统下可以从ActiveState下载ActivePerl并安装。

命令行中双引号中的内容是一个正则表达式,“s/搜索/替换/参数”格式用于搜索和替换。参数中的g表示全局替换,如果不指定g的话,每次搜索替换过程只会替换第一处(上例的perl命令行每次替换过程处理文件中的一行,所以若不指定g的话便只有每行的第一处匹配会被替换)。搜索部分值得一提的是(\w+)\w可匹配字母数字或下划线,+号表示匹配一个或多个,括号表示捕获其包含的内容。替换中的\1表示第一组括号所捕获的内容。

命令行中最后的一个参数是要修改的文件名。可以指定多个文件名,用空格隔开。在linux环境下,由于一般的shell(如bash)都会自动展开通配符对应的文件名,所以可以直接使用类似*.cs的字符串来匹配多个文件。在Windows的命令行提示符中,尝试直接使用*.cs来匹配多个文件的话,会提示打不开文件的错误信息。不过使用Windows命令行技巧同样可以轻松利用通配符来批量处理多个文件:

FOR %A IN (*.cs) DO perl –p -i.bak -e "s/Nullable<(\w+)>/\1?/g" "%A"

更多细节请参见笔者的文章:使用Windows命令行模式进行文件批量处理(一)使用Windows命令行模式进行文件批量处理(二)

命令行参数-i.bak中的.bak指定为被修改的文件创建备份文件,备份文件的文件名是在原文件名之后加上“.bak”。如果单独使用-i而不带“.bak”,将不会创建备份文件。强烈建议每次都创建备份文件。(注意:我在Windows下使用ActivePerl 5.10版本测试时提示不允许不创建备份文件进行替换,而Ubuntu Linux下的perl 5.10是可以的。)

如果不想深究perl解释器是如何去处理我们指定的每个参数的,只需要每次把双引号中的正则表达式和对应的文件名修改掉就可以实现大部分的批量修改工作了。

本节中介绍了基本的perl单行程序正则表达式替换方法,下节将解释-p –i -e等perl解释器参数的细节并展示一些更复杂的应用实例。

Posted in 电脑网络, 软件开发 | Tagged , | 5 Comments

下载Skype 4.0完整安装版

上个月Skype推出了新的4.0版,相比之前的版本变化不小,界面焕然一新。不过由于在国内访问http://www.skype.com都会被强制重定向到http://skype.tom.com,而TOM-Skype目前为止还停留在3.8版,所以国内大多数人都还没开始使用Skype 4.0。

在华军软件园等国内网站可以下载到Skype 4.0版的安装程序,不过一般都是标准安装包,大概2M多的尺寸,安装过程中还要联网下载,而且下载速度很慢(起码在我的电脑上是这样,深圳电信2M ADSL)。

不过Skype网站提供了完整版的安装程序,下载地址是:http://download.skype.com/SkypeSetupFull.exe,而且目前访问这个地址不会被重定向到TOM-Skype网站。(不过直接使用浏览器下载还是很慢,我改成用迅雷就很快了。)

Posted in 电脑网络 | Tagged | Leave a comment

淘宝旺旺5.7与SQL Server 2008冲突解决办法

最近安装了SQL Server 2008 Express以后,淘宝旺旺启动时一直报错,到淘宝网下载最新版本(5.7)重新安装后问题依旧。上网查了查,发现很多人都遇到了同样的问题,不过只要换成阿里旺旺2008便不会报错了。

阿里旺旺2008可以到http://im.alisoft.com下载。

Posted in 电脑网络 | Leave a comment

在ASP.NET中使用GridView展现父子表数据

ASP.NET中GridView控件用于展现单表数据非常方便,只要简单地进行数据绑定便可。但很多时候,需要在页面上显示父子表数据,每一行父表的记录下方显示一个表格展现字表的数据。下图便是这样的一个例子:

MasterSlaveView

以上图中的订单数据为例,本文将介绍一种简单可行的利用GridView展现父子表数据的方法。

为方便说明,这里没有采用数据库来作为数据源,而是使用简单对象的方式。

创建一个C# ASP.NET测试项目,先定义用于表示订单和订单行的两个类:

订单行:
    public class OrderLine {
public string ProductID { get; set; }
public string ProductName { get; set; }
public int Quantity { get; set; }
public float UnitPrice { get; set; }
public float TotalPrice { get { return Quantity * UnitPrice; } }
public OrderLine( string productID, string productName, int quantity, float unitPrice) { ProductID = productID; ProductName = productName; Quantity = quantity; UnitPrice = unitPrice; }
}

订单:

    public class Order {
public string OrderNo { get; set; }
public DateTime OrderDate { get; set; }
public string Customer { get; set; }
private IList<orderline> orderLines;
public IList<orderline> OrderLines { get { return orderLines; } }
public float TotalPrice { get { float total = 0; foreach (OrderLine line in OrderLines) { total += line.TotalPrice; } return total; } }
public Order( string orderNo, DateTime orderDate, string customer) { orderLines = new List<orderline>();
OrderNo = orderNo; OrderDate = orderDate; Customer = customer; }
}

在default.aspx页面上放一个GridView控件,命名为orderView。禁用自动生成列后,手工一个一个加入数据绑定列分别绑定到Order类的几个标量属性上。最后增加一个模板列,模板列里放入另一个GridView控件用于展现订单行的数据,命名为orderLineView。具体ASP.NET实现代码如下:

    <asp:gridview id="orderView" runat="server" autogeneratecolumns="False">
      <columns>
        <asp:boundfield datafield="OrderNo" headertext="订单号码" />
        <asp:boundfield datafield="OrderDate" headertext="订单日期"
              dataformatstring="{0:yyyy-MM-dd}" />
        <asp:boundfield datafield="Customer" headertext="客户名称" />
        <asp:boundfield datafield="TotalPrice" headertext="价格总计"
              dataformatstring="{0:N2}">
          <itemstyle horizontalalign="Right" />
        </asp:boundfield>
        <asp:templatefield>
          <itemtemplate>
            </td></tr><tr><td align="center" colspan="5">
            <asp:gridview id="orderLineView" runat="server"
                  autogeneratecolumns="false"
                  datasource='<%# Bind("OrderLines") %>' width="90%">
              <columns>
                <asp:boundfield datafield="ProductID" headertext="产品编码" />
                <asp:boundfield datafield="ProductName" headertext="产品名称" />
                <asp:boundfield datafield="Quantity" headertext="数量" />
                <asp:boundfield datafield="UnitPrice" headertext="单价"
                       dataformatstring="{0:N2}">
                  <itemstyle horizontalalign="Right" />
                </asp:boundfield>
                <asp:boundfield datafield="TotalPrice" headertext="合计"
                       dataformatstring="{0:N2}">
                  <itemstyle horizontalalign="Right" />
                </asp:boundfield>
              </columns>
            </asp:gridview>
          </itemtemplate>
        </asp:templatefield>
      </columns>
    </asp:gridview>

上面的代码中,几个绑定到Order类标量属性上的字段很好理解,这里就不解释了,这里着重说明一下第9行到第27行所定义的一个模板列。模板列,顾名思义,就是定义一个模板,GridView依照模板来产生要显示的内容。<ItemTemplate></ItemTemplate>标签对中便是模板定义的区域了。可以看到,上面的代码中,模板列的主体是一个命名为orderLineView的GridView控件,所以,针对每一行订单数据,由这个模板列定义的单元格都由GridView控件来展现一个表格。orderLineView内部各数据绑定列的内容这里也不做解释了。要注意的是第13行中的DataSource属性定义,<%# %>标签对中的Bind( "OrderLines" ) 方法将OrderLines绑定到了orderLineView上,由于Order类中的OrderLines属性是一个List,所以这样的绑定是可以正常工作的。

由于正常情况下,GridView只会为每一行数据产生表格中的一行,所以上面代码中的的第11行,在orderLineView控件之前,做了一些特殊的处理,先用</td></tr>关闭GridView自动产生的行,然后再用<tr><td colspan="5" align="center">开了一个新行,之后GridView自动产生的</td></tr>关闭的将是我们在模板列中定义的这个新行。新行中只有一个列,所以通过colspan="5"使它横跨了整个表格。其实这样的特殊处理也是无奈之举,用的是类似欺骗的手法来绕过了GridView的限制。不过在没有更好的而且也很简洁方法时,暂且就用这个办法吧。

好了,页面设计好了,运行时只要把数据绑定到控件上就可以便可以显示出本文开头处的图片中的那个表格了。以下的代码在Page_Load事件中准备一些数据并绑定到了orderView上:

    protected void Page_Load(object sender, EventArgs e)
    {
IList orders = new List();
Order order = new Order("2009010100001", new DateTime(2009, 1, 1), "九九志 • 重阳"); order.OrderLines.Add(new OrderLine("P0001", "GBA", 2, 500)); order.OrderLines.Add(new OrderLine("P0002", "PSP", 1, 1500)); order.OrderLines.Add(new OrderLine("P0003", "NDSL", 13, 1100)); orders.Add(order);
order = new Order("2009010300001", new DateTime(2009, 1, 3), "www.99log.com"); order.OrderLines.Add(new OrderLine("P0002", "PSP", 3, 1450)); order.OrderLines.Add(new OrderLine("P0004", "XBOX 360", 1, 2500)); orders.Add(order);
order = new Order("2009010300002", new DateTime(2009, 1, 3), "Yin Peng"); order.OrderLines.Add(new OrderLine("P0005", "LCD", 1, 1999)); order.OrderLines.Add(new OrderLine("P0006", "CPU", 1, 500)); order.OrderLines.Add(new OrderLine("P0007", "RAM", 4, 80)); order.OrderLines.Add(new OrderLine("P0008", "HDD", 2, 450)); orders.Add(order);
orderView.DataSource = orders; orderView.DataBind();
}

以上简单的介绍了一种使用GridView来展现父子表数据的方法。本文的目的只是通过一个简单的实例来展示这种方法的原理,基于此原理,还可以灵活应用其他技巧,比如,在每条主表记录前加上一个+/-号,用于显示和隐藏字表等等。

Posted in 软件开发 | Tagged , | Leave a comment

速度很快的一个国内Ubuntu源

最近一段时间以来好像cn99的源连接不上,只好去找找新的更新源。试用后发现,http://mirror.lupaworld.com的源速度非常快,我在家里用2M带宽的ADSL下载速度基本上到在200到220KB之间,基本上达到2M ADSL的极限速度了。

要使用http://mirror.lupaworld.com作为Ubuntu的更新源,只需要修改/etc/apt/sources.list,增加相应的配置就可以了。

Ubuntu 8.10版本,增加以下内容:

deb http://mirror.lupaworld.com/ubuntu intrepid main restricted universe multiverse
deb http://mirror.lupaworld.com/ubuntu intrepid-security main restricted universe multiverse
deb http://mirror.lupaworld.com/ubuntu intrepid-updates main restricted universe multiverse
deb http://mirror.lupaworld.com/ubuntu intrepid-backports main restricted universe multiverse
deb http://mirror.lupaworld.com/ubuntu intrepid-proposed main restricted universe multiverse
deb-src http://mirror.lupaworld.com/ubuntu intrepid main restricted universe multiverse
deb-src http://mirror.lupaworld.com/ubuntu intrepid-security main restricted universe multiverse
deb-src http://mirror.lupaworld.com/ubuntu intrepid-updates main restricted universe multiverse
deb-src http://mirror.lupaworld.com/ubuntu intrepid-backports main restricted universe multiverse
deb-src http://mirror.lupaworld.com/ubuntu intrepid-proposed main restricted universe multiverse

Ubuntu 8.04版本,增加以下内容:

deb http://mirror.lupaworld.com/ubuntu hardy main restricted universe multiverse
deb http://mirror.lupaworld.com/ubuntu hardy-security main restricted universe multiverse
deb http://mirror.lupaworld.com/ubuntu hardy-updates main restricted universe multiverse
deb http://mirror.lupaworld.com/ubuntu hardy-backports main restricted universe multiverse
deb http://mirror.lupaworld.com/ubuntu/ubuntu-cn hardy main restricted universe multiverse
deb-src http://mirror.lupaworld.com/ubuntu hardy main restricted universe multiverse
deb-src http://mirror.lupaworld.com/ubuntu hardy-security main restricted universe multiverse
deb-src http://mirror.lupaworld.com/ubuntu hardy-updates main restricted universe multiverse
deb-src http://mirror.lupaworld.com/ubuntu hardy-backports main restricted universe multiverse

以上的配置行我都加在其他deb和deb-src之前了,这样可以优先使用。

Posted in 电脑网络 | Tagged | Leave a comment

MySQL大批量数据插入

公司有一个项目,需要频繁的插入数据到MySQL数据库中,设计目标要求能支持平均每秒插入1000条数据以上。目前功能已经实现,不过一做压力测试,发现数据库成为瓶颈,每秒仅能插入100多条数据,远远达不到设计目标。

到MySQL官方网站查了查资料,发现MySQL支持在一条INSERT语句中插入多条记录,格式如下:

INSERT table_name (column1, column2, ..., columnN)
        VALUES (rec1_val1, rec1_val2, ..., rec1_valN),
                (rec2_val1, rec2_val2, ..., rec2_valN),
                ... ...
                (recM_val1, recM_val2, ..., recM_valN);

按MySQL官方网站,用这种方法一次插入多条数据,速度比一条一条插入要快很多。在一台开发用的笔记本电脑上做了个测试,果然速度惊人。

测试环境:DELL Latitude D630, CPU T7250 @ 2.00GHz, 内存 2G。Windows XP Pro中文版SP2,MySQL 5.0 for Windows。

MySQL是新安装的,建立了一个名为test的数据库,在test数据库建了一个t_integer表,共两个字段:test_id和test_value,两个字段都是INTEGER类型,其中test_id是Primary Key。

准备了两个SQL脚本文件(写了个小程序生成的),内容分别如下:

 

-- test1.sql
TRUNCATE TABLE t_integer;
INSERT t_integer (test_id, test_value)
        VALUES (1, 1234),
                (2, 1234),
                (3, 1234),
                (4, 1234),
                (5, 1234),
                (6, 1234),
                ... ...
                (9997, 1234),
                (9998, 1234),
                (9999, 1234),
                (10000, 1234);
-- test2.sql
TRUNCATE TABLE t_integer;
INSERT t_integer (test_id, test_value) VALUES (1, 1234);
INSERT t_integer (test_id, test_value) VALUES (2, 1234);
INSERT t_integer (test_id, test_value) VALUES (3, 1234);
INSERT t_integer (test_id, test_value) VALUES (4, 1234);
INSERT t_integer (test_id, test_value) VALUES (5, 1234);
INSERT t_integer (test_id, test_value) VALUES (6, 1234);
... ...
INSERT t_integer (test_id, test_value) VALUES (9997, 1234);
INSERT t_integer (test_id, test_value) VALUES (9998, 1234);
INSERT t_integer (test_id, test_value) VALUES (9999, 1234);
INSERT t_integer (test_id, test_value) VALUES (10000, 1234);

以上两个脚本通过mysql命令行运行,分别耗时0.44秒和136.14秒,相差达300倍。

基于这个思路,只要将需插入的数据进行合并处理,应该可以轻松达到每秒1000条的设计要求了。

Continue reading

Posted in 软件开发 | Tagged , | 3 Comments

太爽了,1999元入手28寸宽屏液晶显示器!

最近家里那台老掉牙的用了近七年的AOC 17寸CRT显示器开始时不时罢半夜凉初透工黑屏,拍一拍才能恢复一会儿,实在是无法忍受了,决定换一台显示器。正好最近液晶显示器价格降得厉害,看到很多商家都打出了8xx元买19寸液晶的横幅,虽然一直不太喜欢液晶的显示效果,但是看在价格的份上,决定买台液晶。

昨天在网上查了很久,就在各种品牌型号中一直拿不定主意时,看到了太平洋电脑网有消息称瀚视奇28寸液晶降价到1999元。这个价格太吸引人了,于是找到两家深圳的经销商,打电话过去一问,报价却是2999元。我说网上不是已经报1999元了吗,他们说不清楚,如果想买的话2850可以卖给我。难道是网上的消息有误?

既然如此,还是继续在预先计划的19寸和22寸中选择吧。先是看中了LG L227WTP,22寸的,报1799元送一个Black Yak登山包,号称是LG的22寸“机皇”,各项参数都不错,网上评价也还很好,有点动心,但是觉得价格有点贵,而且分辨率未达到Full HD的标准。继续比较后又在候选列表中增加了明基的T2200HD,22寸的,价格大概在1200多元,参数上稍不如LG L227WTP,不过是16:9的比例,分辨率1920x1080,全高清;优派的VX1962wm和VX1940w,19寸,价格分别在1200元和1000元左右,对比度,响应速度等参数也都不错,而且分辨率达到1680x1050,比一般的19寸的1440x900要更清晰,达到了LG L227WTP的分辨率。

定好了候选型号,今天上午便跑到华强北准备出手。走进宝华大厦,谁知第一眼看到的竟然是瀚视奇的展台,工作人员正在布置展台,而且展示的28寸液晶价格正式传说中的1999元,问了问工作人员,说是今天开始的促销活动,就搞两天。最终没有抵御住低价的诱惑,立马便出手扛了一台回家,把之前的候选列表全部抛到九霄云外了。

这款瀚视奇HG281D虽说价格便宜,参数上看却也不算差,一下是从太平洋电脑网摘抄的资料:

 

基本参数
型号

HG281D

尺寸

27.5英寸

点距

0.309mm

接口类型

15针 D-Sub,HDMI,音频输入输出接口

性能参数
亮度

500cd/m2

对比度

2400(动态):1

分辨率

1920*1200

响应速度

3ms

水平可视角度

160度

垂直可视角度

160度

面板最大色彩

16.7M

面板类型

TN

其它参数
麦克及音箱

内置麦克风,2*2.5W扬声器

耗电功率

100W

认证规范

3C认证,Windows Vista Premium,TCO 06,能源之星

其它性能

支持DVI转接,底座旋转设计

附带的连接线也很全,一条VGA线,一条HDMI转DVI线,还有一条VGA转分量线。除了普通的3.5mm音频线外,还带了一条3.5mm转R/L的转接线。搬回家好,我把两台主机都接了上去,一台接VGA,一台通过HDMI转DVI线接到了HDMI口,可以在两台主机之间切换。另外,由于内置了音箱,配合VGA转分量线和3.5mm转R/L的音频转接线,直接就可以接上高清机顶盒,或是DVD,游戏机等了。可惜我的机顶盒不是高清的,游戏机也还是老一辈的PS2和XBOX,所以暂时这台显示器还是电脑专用吧。

最后,放上一张随手拍下的照片,屏幕上的保护膜还没拆。

HG281D

Posted in 电脑网络 | 3 Comments