2007年12月13日星期四

MikTex's FNDB

阅读MikTex帮助文件——“为了加速文件搜索,MikTex使用一个已知文件列表来搜索文件。该列表称为 file name database(FNDB)。强烈建议当你在TEXMF目录中添加或删除文件后,用MikTex提供的工具来刷新一下该文件列表。”郁闷,并没有告诉我怎么通过命令行刷新这个文件列表。

2007年12月5日星期三

Windows脚本技术

Windows与Unix/Linux所不同的根本所在是设计目的,前者为非专业人士设计,图形界面(GUI)是根本;而后者则关注功能实现,命令行(Console)才是根本。所以在Unix/Linux上脚本编写是件很容易的事,但到了Windows上则成难事。其难有三:一则Windows中大部分软件都是基于GUI的,你很难用命令行将其“串联”起来;二则Windows中脚本多要涉及COM等概念,对于Windows的结构体系要有很多的了解方能“游刃有余”;三则MSDN中虽然有相关的脚本介绍,但比较分散,没有系统性,样例程序又很少,这给学习与使用带来很多问题。

我近日要解决一个问题,能自动将某个Zip包中的多个PDF文件解压后分解成页,筛选掉重复的页然后再合并成一个PDF。原以为在两日内就能完成的脚本程序,竟用了一周的时间。现在将其间的思考与经验进行总结:

1.在Windows中有四类脚本。

(1)命令行,就是Windows自带的一些命令,如for等,这些命令可以构成最简单的批处理,特别是For命令,使用得当会起到事半功倍的效果。比如要将某个文件夹中所有的.htm文件后缀名修改成.html,用rename *.htm *.html是不行的,可以用 for %i in (*.htm) do rename %i %il 来实现。如果要将for命令写入BAT文件,则应该为 for %%i in (*.htm) do rename %%i %%il 。

(2)WSH脚本,这是Windows中最常用的一类脚本,也是Windows平台内置的最强大的脚本系统。WSH,即Windows Script Host,其基于COM技术框架,可调用Windows平台内嵌的几个强大的COM对象,最常见的是“WScript.Shell”,“Scripting.FileSystemObject”,“ADODB.Connection”“ADODB.Command”,熟悉COM编程、ASP的人应该对此不陌生。其优点在于可以用VBS或JS等比较高级的语言来编程而不仅仅是命令行的累积。其缺点是调试很困难。
由于其与COM的内在联系紧密,所以有时人们会在BAT文件中临时创建一个VBS文件,然后调用该VBS文件以实现BAT所无法实现的功能,其基本结构如下:

@echo. >>sample.vbs ::创建一个sample.vbs文件,并写入一个空行
@echo WScript.Echo "Hello,WSH World">>sample.vbs ::这里将vbs中的代码写入文件中
.......
@echo. >>sample.vbs ::再写入个空行
@cscript //I //nologo sample.vbs ::调用该vbs脚本
@del sample.vbs ::删除该脚本

(3)基于动态语言环境,如Python,Ruby等。这样的动态语言一般都有与平台交互的对象库,通过动态语言来编写程序,易于调试与OOP化,复用性高,健壮性强,移植性好。但其要学习一门动态语言有些难度,而且对于一些临时性的简单工作也显得“大材小用”。如果要编写一些最常用且要不断修改的程序,基于动态语言是首选。

(4)一些特殊的自动化程序,如AutoIt,AHK(Auto Hot Key)等。这些软件其实就是一个解释器,可以将你编写的脚本进行解释运行。由于它们是完全面向Windows编写的,对于Windows的GUI支持的很好,而且有很强大的辅助编写脚本功能(如将鼠标动作录制成脚本等)这样就极大方便了GUI的自动化。所以如果面对许多GUI操作时,这类脚本当是最好选择。当然由于这些脚本语言具有一些特定性,在编写时仍需要熟悉其函数库;而且这些脚本是与Windows紧密相连的,其无法像动态语言脚本那样可以简单地移植到其它平台上。

2007年10月8日星期一

PDFTK的样例

PDFTK是一款PDF的命令行工具,其可以完成许多PDF合并、分割工作。
下面是我从网络上摘得的PDFTK的样例,翻译列表如下:

Merge Two or More PDFs into a New Document
将两个或多个PDF文件合并到一个文件中
pdftk 1.pdf 2.pdf 3.pdf cat output 123.pdf

or (Using Handles):
或者采用句柄
pdftk A=1.pdf B=2.pdf cat A B output 12.pdf

or (Using Wildcards):
或者通配符
pdftk *.pdf cat output combined.pdf

Split Select Pages from Multiple PDFs into a New Document
在所选PDF文件中选择页面合并到新的文件中
pdftk A=one.pdf B=two.pdf cat A1-7 B1-5 A8 output combined.pdf

Encrypt a PDF using 128-Bit Strength (the Default) and Withhold All Permissions (the Default)
用128位密码(默认值)加密PDF并封锁所有权限(默认值)
pdftk mydoc.pdf output mydoc.128.pdf owner_pw foopass

Same as Above, Except a Password is Required to Open the PDF
与上面相同,但不需要PDF文件打开密码
pdftk mydoc.pdf output mydoc.128.pdf owner_pw foo user_pw baz

Same as Above, Except Printing is Allowed (after the PDF is Open)
与上面相同,但不允许打印(在PDF打开后)
pdftk mydoc.pdf output mydoc.128.pdf owner_pw foo user_pw baz allow printing

Decrypt a PDF
解密PDF
pdftk secured.pdf input_pw foopass output unsecured.pdf

Join Two Files, One of Which is Encrypted (the Output is Not Encrypted)
合并两个文件,其中一个是加密的(输出文件不是加密的)
pdftk A=secured.pdf mydoc.pdf input_pw A=foopass cat output combined.pdf

Uncompress PDF Page Streams for Editing the PDF Code in a Text Editor
解压PDF页面流以便于在文本编辑器中编辑PDF代码
pdftk mydoc.pdf output mydoc.clear.pdf uncompress

Repair a PDF's Corrupted XREF Table and Stream Lengths (If Possible)
修理PDF损坏的XREF表格和流长度(如果可能的话)
pdftk broken.pdf output fixed.pdf

Burst a Single PDF Document into Single Pages and Report its Data to doc_data.txt
将单个PDF文件各页拆开,并将数据汇报到文本文件中
pdftk mydoc.pdf burst

Report on PDF Document Metadata, Bookmarks and Page Labels
将PDF文件的元数据、书签和页码标号输出到文本文件
pdftk mydoc.pdf dump_data output report.txt

2007年9月9日星期日

用Wink制作帮助教程

今天在善用佳软上看到一个小型的屏幕捕捉软件Wink,才2M大小,下载安装后试用一下的确不错。主要是其免费且生成Flash格式文件,很适合我这样的“懒于文笔”描述的人来使用。

2007年9月4日星期二

Latex-Suite 4步安装(根据官方稿翻译)

1.下载并解压缩文件
到 http://vim-latex.sourceforge.net/ 下载压缩包,并解压到你的~/vimfiles目录(Windows)或者~/.vim目录(*nix)中。如果你已经很久没有升级了,最好应先移除~/vimfiles/ftplugin/latex-suite目录再安装
注意:如果你已经安装一些Latex文件拓展,则应阅读 高级安装 以避免覆盖某些你既有文件。
2.在.vimrc配置中增加特定内容

" REQUIRED. This makes vim invoke Latex-Suite when you open a tex file.
filetype plugin on

" IMPORTANT: win32 users will need to have 'shellslash' set so that latex
" can be called correctly.
set shellslash

" IMPORTANT: grep will sometimes skip displaying the file name if you
" search in a singe file. This will confuse Latex-Suite. Set your grep
" program to alway generate a file-name.
set grepprg=grep\ -nH\ $*

" OPTIONAL: This enables automatic indentation as you type.
filetype indent on

3.安装帮助文件
要安装帮助到Vim中,应启动Vim并:
helptags ~/.vim/doc (*nix)或 helptags ../vimfiles/doc(windows)
4.完成!
安装完成,现在Latex-Suite可以自动启动,你可
:help latex-suite.txt 来阅读在线帮助

2007年9月2日星期日

用Python来分析《新东方背单词》的录入格式

我想使用《新东方背单词》来背一些自己浏览文章时遇到的生词。该软件提供了一个建立自己图书并从文本格式文件批量录入的功能,但在帮助中没有提供详细的格式说明。于是我用Python编写了一个简单程序来生成测试文本,找到其中规则。代码如下:


# Recite words
sl = []
sll = []
for i in range(26):
sl.append( chr( ord('a') + i ) )
for i in sl:
for j in sl:
sll.append( i + j )
f = open('recite.txt','w+')
f.write('w \n')
for i in sl :
if i <> 'w' :
f.write( '<' + i + '>' + i + '\n' )
f.close()
f = open('recite1.txt','w+')
f.write('ww \n')
for i in sll:
f.write('<' + i + '>' + i + '\n' )
f.close()



生成的文件录入《新东方背单词》后显示对应的格式,从而得到格式定义符如下:

w--单词
c--中文解释
e--英文解释
d--短语
p--音标
f--词频
k--考点
h--助记法
s--同义词
a--反义词
o--其它
ee--例句

《Seven Habits of Effective Text Editing 2.0》阅读笔记

1.这不是Vim操作入门,其没有介绍Vim的基本知识,而是集中于编辑器的使用方法,这些方法也可在其它编辑器中使用。
2.要充分认识到编辑器的作用,既不能漠视编辑器的功能而用“蛮力”来完成工作,但也不要面面俱到地学习编辑器所有功能。对于Vim和Emacs这样的骨灰级编辑器来说,完全学习是"Mission Impossible"。
3.建立一个良好的习惯很重要,但更重要地发现问题,并能用智慧地方式进行解决的勇气与耐心。我们往往会有很多好的提高效率的想法,但在工作或学习的压力下,常不能坚守,而白白失去提升的机会。所以本文中非常强调发现的过程,即发现问题与发现解决方案。
4.方案不要一步完美,这样的方案往往不存在(或在我们头顶的三万公尺上)。要有踏出第一步的勇气,先建立一个力所能及但又有所提高的方案,这样即能增强信心,又为进一步完善提供基础。在不断地完善中学习编辑器,用好编辑器。
5.查找与修正是编辑中最常用的功能。用好编辑器的试金石是检查自己是否能自如地利用编辑器功能来快速查找定位与修正。而正则表达式的知识是非常关键的。在Windows下成长的一代似乎没有Unix/Linux人们与生俱来的模式观念,而模式在正则表达式中是最基本的。要努力锻炼这样的思维,虽然起步比较吃力,但终身收益。
6.编辑器好似兵器,而运用编辑器的方法则是每个人的内功。如果内功不强,即是神兵利器在手也发挥不了作用;而如果内功强劲,那么简单的编辑器也能发挥大作用。努力改变自己的思维,发现、创新、提升、再发现是每日必修的内功。

2007年8月28日星期二

GNU Make学习(1)

1.Make是一个“古董级”的工具,其像橡树年轮,记录了近三十年计算机科学进步的痕迹。或许在学习Make中你会如考古般发现新奇的过往智慧,但更多的时候你将迷失于旧与新的迷雾之中,这也正是Make对于Windows平台下成长的一代程序员来说难懂的原因。但在每个IDE的F5或F9的背后,都能找到Make的身影。要进阶编程功力,当从了解Make开始。

2.Make是一个工具,它完成两个任务:一是建立一个多个文件的关系图,其用来描述文件间的依赖关系;二是检测文件的新旧,并按照关系图来进行命令执行以完成局部或整体的更新工作。所以在Make中存在两类语言,一为建立关系图,一为进行文本处理。

3.在学习Make前,应了解本机上的Make环境。在Windows系统中,由于安装BCB、VC2005等都会自带Make工具。而本文所用的Make是GNUMake 3.8,在Cygwin和DevCPP中都有。不同的Make对应不同的语法,故在BCB中由bpr文件导出的Make文件不能在GNUMake下编译。我就是犯了一次这样的错误。

4.Make中最简单的方式就是通过显性说明来建立关系图。对于小项目这还是很不错的方案,但对于大项目则不行。原因有三:一是重复声明过多,代码冗余,不利于维护;二是声明过细,移植性差;但最重要的是往往文件关系复杂到无法通过人脑来进行关系声明,这就必须用一种计算机辅助方式来进行关系推衍,这在Make中称为“Rule(规则)“。

5.Makefile难于阅读与调试的原因在于其自上而下的书写格式与”(关系图)自底而顶“的执行顺序往往是不一致的,也是人难于掌握的。所以Makefile采用Target(目标)与Rule(规则)这两种机制来分割问题。要注意的是这两种机制是双刃剑,其使用不当往往会造成Makefile的更晦涩难懂。

6.Phony Target用于结构化Makefile,将问题分割,并可优化用户界面。而其中的Empty Target则用来控制命令执行范围,避免非更新区域的反复执行。而对于大项目,制定一个Help Phony是常用技巧。但Phony Target也会破坏一些自然逻辑结构,从而给阅读带来一些障碍。要适当应用Phony Target,不要采用特殊技巧,在欺骗Make工具的同时也会欺骗阅读者,可能包含未来的你。

7.Rule则屏蔽了关系图的细节,让计算机来自动铺砌关键帧间的空隙。所以良好的Rule即能提高阅读性,又能提高执行效率。

8.Make诞生于Unix,其带有很强的*nix家族的色彩。比如其支持的通配符(WildCards)与Bourne Shell相同,包括~,*,?,[...]和[^...]。其有着古旧的键缩进惯例。

9.在Makefile中要注意变量展开、宏展开和函数展开的顺序。要充分理解Automatic Variables(自动变量)的作用;要用VPATH来指定被搜索文件的目录;要善于利用正则表达式来处理文本变量问题,特别是在gcc -M问题上。要小心地分割项目,善于利用eval函数来达到特定要求。

10.注意递归变量的声明与使用,这些变量与C中指针相似。

11.变量用$()来取值,摈弃过时的${}方式。

12.注意Command的Comment(前面有)与Makefile的Comment间的差异

13.正是有了简洁而强有力的函数支持,GnuMake具有很强的文本处理能力;而定义良好的自定义函数或宏,可提高Makefile的通用性和移植性。

14.inline函数是最常见的形式。

15.命令修改符 @-消音;- 消噪音(埋头工作) + 无论如何都要工作(即便是--just print模式)

2007年8月23日星期四

新读《C++Primer4》

虽然《C++Primer3》是我的枕边常读之书,但这次《C++Primer4》仍给我许多新的启发。该版进一步强调了C++作为一门工程语言的实用性。如在章节设置上,第一部与第二部都没有叙述Class的定义等内容,而是从使用者角度介绍STL中最常用库的介绍。这表明作者认为目前C++程序员更应该了解STL库,去用STL库,而不总是去设计“原始而拙劣”的Class。在第一部Basic中,作者将String、Vector等STL中最常用库介绍放在语句表达式之前介绍,并将Array与Pointer并入一章叙述,都体现了这一点。想现在大学中,许多学生学习完C++后,对于 Bind、Transform 等知之甚少,而 Class 也编写得很糟糕,就更感到《C++Primer》作者的真知灼见。“用比创建好”——这是《C++Primer4》给我的最深印象。

2007年8月20日星期一

网页上的代码高亮

在网络上发现一个源自Google的工具,可进行代码高亮。
1.下载并解压文件包,其中有两个文件:CSS和JS
2.在HTML文件头引用CSS与JS
< link href="prettify.css" type="text/css" rel="stylesheet">
< script type="text/javascript" src="prettify.js"></script>
3.在HTML正文中执行JavaScript命令,如 < body onload="prettyPrint()"> < /code >
4.需要高亮的代码用< code class="prettyprint" > ... < /code >包围即可。
原文地址:
http://google-code-prettify.googlecode.com/svn/trunk/README.html

2007年8月19日星期日

lstlisting的使用技巧

lstlisting中使用lstinputlisting命令导入外部源代码,不要全部导入,这样常会引起Latex解释错误。应定义起始/结束行号,这样即清楚,Latex编译也很快。
\lstinputlisting[language=Gnuplot,firstline=1,lastline=2]{sample01.plt}

2007年8月18日星期六

Firefox中的Gmail显示

最近Firefox中Gmail总是显示不正常,但在IE中却能正常显示,我原先以为是Firefox升级后的问题,今天Google得知原来是ADblock的缘故,故在ADblock中增加两条新的过滤条目后即可。

@@|http://*.google.com/
@@|https://*.google.com

2007年8月3日星期五

《C++沉思录》阅读笔记(5)

1.在一个具有继承关系的类群中使用容器会遇到许多在使用内在类型(元类型)时所不会遇到的问题,因为机器是不了解它要处理的问题的规模是多大。它像一个满脸青春痘的少年面对制定一个跨国企业下年度财务预算报表时一样茫然无措。这并不是说少年不够聪明,而是他没有多少经验。即便对于一个经过多年磨炼的人来说,面对一个无法预测边界的工作时,他多少也会紧张。
2.将继承与容器共用,迫使我们要处理两个问题:控制内存分配和把不同类型的对象放入同一个容器中。这其实是一个RTTI问题。在C++中的语言层次,并没有提供一个完善的RTTI解决方案,但其确提供了解决该问题的工具。可惜地是,该问题是OOP中最常见也是最难于理解的问题,故后来的Delphi、Java、C#等都将RTTI作为语言级机制内化起来。这固然为新手入门带来很多好处,并能大幅提高软件工业的生产效率。但软件生产是一个如此特殊的产业,了解RTTI等底层技术的人的产能可能是一般新手的几百倍。或许其只是在产生了形式上的"效率提高"的繁华,而实际整体并没有太多增长。
3.在容器中应该使用代理对象而不是对象本身。
4.在编辑器中手工编写一下代码,有时不需要编译就可以理解作者意图,而单纯阅读总像"雾里看花"。
5.不应该接受对象,而应该接受对象指针或者引用。这虽然带来显而易见的效率优势,也带来棘手的问题,因为使用对象指针比直接使用对象要困难,未初始化的指针是非常危险而且没有什么简单办法可以防范。所以要在其间增加一个代理类,将指针管理封装起来,这样就有效隔绝了指针问题的蔓延。
6.Handle类的实现越看越和COM机制相似,或许COM的实现就是采用这样的技术。
7.Copy on write技术能有效提高效率,在编写完成代码后,应该用该技术优化既有代码。

《C++沉思录》阅读笔记(4)

1.OOP->使用继承和动态绑定的编程方式;
2.检查表不是任务清单,它的用途是帮助你回忆起可能会忘掉的事情,而不是来约束你;
(1)构造函数
(2)私有数据成员
(3)带参数的构造函数
(4)是否每个构造函数都初始化所有的数据成员
(5)析构函数
(6)虚析构函数
(7)需要复制构造函数
(8)赋值操作符
(9)赋值操作符能正确地将对象赋值给对象吗?
(10)定义关系操作符
(11)删除数组时采用delete[]
(12)在复制构造函数与赋值操作符参数中使用const
(13)如果函数有引用参数,其应该是const吗?
(14)适当声明成员函数为const
3.C++更适合于那些喜欢思考的程序员;

《C++沉思录》阅读笔记(3)

1.Murphy's Law 墨菲法则,一件事只要有可能变糟,就一定会变糟。
2.通常我们不可能为特定的工具挑选合适的问题;而应该为特定的问题挑选合适的工具,但目前我们常常会在没有分析问题前就决定了工具,这常常是因为商业意义或其它原因。有时我会在第一次技术讨论会上,在一段5分钟的简短需求说明后,听到项目经理斩钉截铁地提出要采用J2EE+***或者ASP.NET+***等方案,然后兴致勃勃地讲述该技术平台的优越性,宛然他是某家技术提供商所雇用的推销员。
3.C++主要设计目的是可移植性和可并存性,其可移植性与跨平台不是一个概念。在Java以前就有许多包裹着不同层次系统的语言,很显然Java是其中最成功的一个,而其由于商业推广目的,并不会强调移植性与跨平台间的概念差异。虽然从计算机科学家的角度来看,这样的差异是如此之大,以至于许多专家认同"Java不是跨平台,Java自己就是平台"。但对于程序工人来说,这样的差异是细小的。而对于商人来说,这样的差异是产生"现金流"的风道。
4.C++的目的不是安全,而是自由。我想随着软件工业的发展,C++与Java会不断分化,科学家使用C++,而商业系统中的技术工人则采用Java(或者与之类似的C#等)。

《C++沉思录》阅读笔记(2)

1.很多最成功、最有名的软件最初都是由少数人开发的;
2.软件业中,软件制造的规模和经济效益不成正比;
3.抽象是机器所不易而是人所擅长的工作,不同层次的抽象产生不同层次的系统,要厘清不同语言能赋予人不同的层次的抽象能力。有些抽象不是语言的一部分。
4.在某处很显然的约定在另一写地方会成为"隐讳"的细节而不为自己和他人所觉察、最终成为最难于Debug的Bug。
5.人应该成为工具的主人而不是依附工具的奴仆。

2007年8月2日星期四

C++沉思录阅读笔记(1)

实用和抽象是C++的本质特性。不要陷入教条主义的泥潭,但要尊重编程手册与智慧。在面对代码时要始终保持实用主义原则,而在确保程序正常工作的基础上,敢于挑战自我,用眼光考察代码的未来,用头脑抽象问题的本质。对于一个优秀的C++科学家来说。编程应是(1)集中考量问题的本质(2)定义一个类来抓住本质,确保其能工作(3)将其逐步抽象建立一个更一般问题的解决方案(4)在遇到符合这个本质的问题就采用该类。
思索是C++程序员的特权,因为从语言角度C++给于程序员最大的自由度。

2007年7月1日星期日

python过滤HTML代码小记

我常用Python来过滤HTML代码,其中一项工作是将网络上批量下载的文章进行重命名。一般操作是先下载索引页面(HTML),然后用FlashGet批量下载文件;用Python过滤索引页面以获取文件下载名与实际文件名的对应列表,最后转换为BAT文件批处理。
但我一直没有能解决如何判断A标签的class属性问题,因为我以前的代码是:
def start_a(self,attrs):
idText = [ v for k, v in attrs if k == 'class' ]
fileHref = [ v for k, v in attrs if k == 'href' ]
print fileHref
if idText == 'a': #这里判断class的属性,有问题的
self.inValid = True
self.fileHrefs.append( fileHref )
def end_a(self):
self.inValid = False
其中判断A标签的class属性那段是有问题的。原因是我没有区分Python中数组与字符串的关系。今天我重读Python帮助后才意识到这一点。我的新代码如下:
def start_a(self,attrs):
idText = [ v for k, v in attrs if k == 'class' ]
fileHref = [ v for k, v in attrs if k == 'href' ]
print fileHref
if idText == ['a'] : #用数组来判断
self.inValid = True
self.fileHrefs.append( fileHref [0]) #在序列数组中添加字符串而非子序列数组
def end_a(self):
self.inValid = False
这样就解决问题了。

2007年6月25日星期一

批量下载后的文件名过滤

用FlashGet批量下载文件后面临一个文件名更改过滤的问题。我的解决方案是:
1.在批量下载时,同时下载该网页的HTML文件;
2.用Python来过滤出对应的HTML文件;
3.将过滤文件修补成Bat文件,运行后则可批量更改名称;
=====================================================================
Python过滤源代码
# -*- coding: cp936 -*-
# yankchina@gmail.com
# 2007-06-26 pass

from sgmllib import SGMLParser
class MyHtmlFilter(SGMLParser):
def reset(self):
SGMLParser.reset(self)
self.inValid = False
self.fileHrefs = []
self.fileNames = []

def start_a(self,attrs):
#idText = [ v for k, v in attrs if k == 'class' ]
fileHref = [ v for k, v in attrs if k == 'href' ]
#if idText == 'a01' :
self.inValid = True
self.fileHrefs.append( fileHref )
def end_a(self):
self.inValid = False


def handle_data(self, text ):
if self.inValid:
self.fileNames.append( text )


def FilteHtmlFile( inFileName,outFile ):
''' Filte Html File

'''
import os
if os.path.exists( inFileName ):
inFile = open( inFileName, "r")
parser = MyHtmlFilter()
parser.feed( inFile.read() )
inFile.close()
parser.close()
print len( parser.fileNames )
for i in range( len( parser.fileNames) ):
outFile.write( parser.fileHrefs[i][0] + " " + parser.fileNames[i]+ ".doc \n " )
print parser.fileNames[i]
print parser.fileHrefs[i]
print inFileName, len( parser.fileHrefs )

if __name__ == "__main__" :
outFileName = 'output.txt'
outFile = open( outFileName, "w" )
htmlFileName = "1.htm"
FilteHtmlFile(htmlFileName, outFile )
outFile.close()

2007年6月21日星期四

AutoIt的学习与开发心得

AutoIt3是一个Windows平台下的自动脚本工具,其脚本语言接近VBScript,但拓展了许多Windows平台的有效功能,如窗体控制、DLL调用、网络开发等。我下载了AutoIt3并进行了短期学习,开发了一个简单的脚本程序,用来在TotalCmd中调用创建一个Readme.txt文档。以前我经常手动创建这样的文档很烦人,而现在看着屏幕上一闪而过的Notepad,自有一种欣慰。
下面是程序脚本:
#cs ----------------------------------------------------------------------------
AutoIt 版本: 3.2.3.14第一版)
脚本作者: yankchina@gmail.com
Email: yankchina@gmail.com
QQ/TM:
脚本版本: 1.0
脚本功能: 新建一个名为Readme.txt的文档,并在文档首部写入日期和作者信息

#ce ----------------------------------------------------------------------------

; 脚本开始 - 在这后面添加您的代码.
Dim $AuthorInfor = "yankchina@gmail.com " ;作者信息
Dim $ReadmeFilePath = "F:\CacheTemp\" ; 默认保存路径
;如果有命令行参数,则取第一个命令行参数为文件保存位置
if $CmdLine[0] > 0 Then
$ReadmeFilePath = $CmdLine[1]
EndIf
Dim $ReadmeFileName = $ReadmeFilePath & "readme.txt"
;判断文件是否存在
Dim $FileIsExist = FileExists( $ReadmeFileName )
;以写模式打开文件,并写入题头信息
$file = FileOpen($ReadmeFileName,1)
; 检查文件是否正常打开
If $file = -1 Then
MsgBox(0, "错误", "无法打开目标文件"&$ReadmeFileName)
Exit
EndIf
;写入标题信息
if not $FileIsExist Then
FileWriteLine($file,"帮助说明文档")
FileWriteLine($file,$AuthorInfor)
EndIf
FileWriteLine($file,"")
FileWriteLine($file, getCommentLine("-",40) )
FileWriteLine($file,@YEAR&"-"&@MON&"-"&@MDAY&" "&@HOUR&":"&@MIN)

FileClose($file)
;运行记事本程序
Run("notepad.exe "& $ReadmeFileName) ;运行记事本程序
if WinWaitActive("readme.txt - 记事本") Then
Send("^{END}") ;下移到文件底部
Send("!+0") ;开启中文输入法
EndIf
;--------------------------------------------------------------------------
;获取一个注释字符串列
Func getCommentLine($CmtChar,$CmtNumber)
$ResultStr = ""
For $i = 0 to $CmtNumber -1
$ResultStr = $ResultStr & $CmtChar
Next
Return $ResultStr
EndFunc
;---------------------------------------------------------------------------

用AutoIt自带工具编译成exe文档后,在TotalCmd中设置一个自定义命令,参数是
%P,这样就可方便地在当前活动目录中创建Readme.txt文件了。

2007年5月17日星期四

Windows下没有图形界面

Windows是以图形界面的方便易用而行销于世,但如果没有图形界面,该如何控制Windows呢?
昨天虾米管的服务器出现问题了,其无法启动“网络连接”界面来设置网卡的IP地址。我怀疑是某个服务进程损坏了。重装Windows是最后一步庸招,当前还不需要使出来。在没有图形界面的时候,命令行是最有效的工具。
我的方法是编写如下Bat文件,通过 netsh interface 命令修改了网卡的IP地址。
netsh interface ip reset name="本地连接"
netsh interface ip set address name="本地连接" source=static addr=*.*.*.* mask=255.255.255.0
netsh interface ip set address name="本地连接" gateway=*.*.*.* gwmetric=1
netsh interface ip set dns name="本地连接" source=static addr=*.*.*.*
netsh interface ip set wins name="本地连接" source=static addr=none

看来在Windows下,学习命令行还是相当有用的。

2007年3月30日星期五

美丽的素数 伟大的证明[转贴]

(来源: 科学网)

公元前3世纪,古希腊数学家欧几里得已经证明素数的数目是无穷的;2004年,陶哲轩和格林证明存在任意长的素数等差数列,他们的发现揭示了素数中存在的某种规律。

在数学家的眼中,素数是美丽的。就像原子之于化学家、DNA之于遗传学家,素数是自然界中全部数的最基本的结构砖块。那么究竟什么是素数呢?也许任何一位小学三年级的学生都会清楚地回答这个问题:在正整数中,除了1以外,只能被自身和1整除的数就是素数,素数从2,3,5,7,11和17开始……

美丽的素数

1,2,3……是正整数,其他数字如负数、有理数则都是以正整数为基础定义出来的,所以,研究正整数的规律非常重要。因为任何一个整数均可表示为素数的乘积,而且这个表示是唯一的,所以,研究清楚素数的问题非常重要,但从素数中是很难得到一条定理的。

公元前3世纪,古希腊数学家欧几里得已经证明素数的数目是无穷的。今天,陶哲轩和格林证明“存在任意长度的素数等差数列”,揭示了素数中存在的某种规律。

什么是等差数列呢?这是一个古老的数学课题。一个数列从第二项起,从后项减去前项所得的差是一个相同的常数,则这个数列就被称为等差数列。比如,1,3,5是一组由三个数构成的等差数列,1,3,5,7则是由4个数构成的等差数列。

用素数构成的等差数列被称为素数等差数列。比如从5开始,以12为间隔常数,就可以得到这样的序列:5,17,29,41,53,65……但对这个数列来说,只有前5个数是素数,因此,5,17,29,41,53是一个由5个素数构成的等差数列。因为65可以被5和13整除,不是素数,所以这个特定的素数等差数列不可能延展到6个数的长度。

问题出现了:由其他素数构成的等差数列会更长吗?答案是肯定的。事实上,199,409,619,829,1039,1249,1459,1669,1879,2089就是间隔常数为210的10个素数构成的等差数列。

而且,数学家们一直认为,由素数构成的等差数列可以任意长,这个猜想提出的时间太长,以至没有人知道这个问题最初是由谁提出来的。但是,在2004年前,没有数学家能证明它。

永不消失的素数

到目前为止,已知的素数等差数列的长度为23,即由23个素数构成的等差数列,而且这还是在当今最先进的计算机上找到的,这个数列的第一个数是 56211383760397,数之间的间隔常数为44546738095860,最后一位数是56211383760397+ 44546738095860×22.

根据上面的描述,一个比较清楚的事实是:随着自然数数值的增加,素数的分布变得越来越稀疏,要寻找这样的等差素数序列就越来越困难。但是,古希腊数学家知道素数是永远不会彻底消失的,自然界中有无穷多个素数。

尽管在正整数中,素数看起来是以一种随机的方式出现的,但在19世纪末,法国数学家雅克。哈达玛达(Jacques Hadamard)和比利时数学家法勒布赛(Charles de la Vallee-Poussin )证明:一种隐藏的规则存在于素数稀疏的背后。换言之,在看似混乱无序的素数数列中,一定存在某种规律。

而存在任意长的素数等差数列则是素数性质中的另外一种规律。尽管数学家一直认为“存在任意长度的素数等差数列”,但到2004年前,还没有人能证明它的存在。

有关这个问题的一个真正的进展出现在1939年,当时,荷兰数学家Johannes van der corput证明:有无穷多个由3个素数构成的等差数列。那么,由4个素数构成的等差数列的数目是不是也无穷多呢?

伟大的证明

英国大数学家Atath Brown证明,由前面三个素数和后面不超过两个素数的乘积构成的4个数的等差数列有无穷多。

1975年,匈牙利科学院的数学家施米列迪(Endre Szemeredi)证明了一个定理。如果简单地解释,这个定理的意思是在任何不会快速稀疏的整数子集中,肯定会有任意长度的等差数列。世界上只有极少数数学家能懂得这个证明,但施米列迪定理不适合于素数,因为,随着自然数的增加,素数的出现会突然变得稀疏。

2002年,两位20多岁的数学家着手证明施米列迪定理在某种特定性质的素数子集中也成立,他们希望能证明:有无穷多个由4个素数构成的等差数列。为了证明这个问题,陶和格林用了两年多的时间分析证明施米列迪定理的4个完整证明的背后因素。

陶哲轩说:“我们研究施米列迪定理并努力推进它,以便它能解决素数的问题。为了实现这个目标,我们借用这4个证明方法来建造一个施米列迪定理的扩展版。每次当格林和我陷入困境时,其中一个证明的思想总能解决我们的问题。”

两年后,用了一个非常漂亮的方法,格林和陶哲轩解决了问题,但结果实在惊人。2004年4月18日,两人宣布:他们证明了“存在任意长度的素数等差数列”,也就是说,对于任意值K,存在K个成等差级数的素数。例如 K=3,有素数序列3, 5, 7 (每两个差2)……K=10,有素数序列 199, 409, 619, 829, 1039, 1249, 1459, 1669, 1879, 2089 (每两个差210)。他们将长达 50页的论文——《素数含有任意长度的等差数列》——张贴在当日的预印本网站上,并向《美国数学年鉴》(Annals of Mathematics)投稿。

这是一项惊人的成就,他们的发现揭示了素数中存在的某种规律。这是一项伟大的成就,他们的证明立即在国际学术界引起轰动。2004年5月21日出版的美国《科学》杂志报道说,“两位数学家用数论中一个令人眩晕的突破结束了一个问题。”

《发现》杂志将陶哲轩和格林在素数方面的研究评选为2004年100项最重要的发现之一;2004年出版的《现代数论导引》已经引用这篇尚未正式发表的论文所涉及的工作。

据最新消息,格林和陶哲轩的这篇论文已被《美国数学年鉴》接受,即将出版。(王丹红/编译整理)

程序员四大忌 你该如何避免[转帖]

来源:希赛社区 更多内容请登陆:http://bbs.csai.cn/bbs/index.asp

一忌:轻易言败,没有自信

  没有永不放弃精神的程序员,只是一个有程序员名号的假程序员。一个真正的程序员,知道在程序设计的过程中,可能会遇到不计其数的困难和问题,可能有极多的挫折和失败,而成功只有一次。

  就为解决一个问题,我们可能连续十几甚至几十小时的坐在计算机前不停的工作。一个问题解决了,可能又有其它的问题出现。而你要是不能坚持下来,可能从前的一切努力都流失了。轻易言败的人请不要做程序员,你不可能成功。执着是最可贵的。

  执着的程序员都是相信自己的人,每时每刻都会鼓励自己,你做的出来,你能解决,你会成功。这样他才能坚持下去。

二忌:浮华不实,自满自大

  夸夸奇谈的人不是优秀的程序员。整个程序设计的过程就是一个研究学习,应用,再研究学习,再应用的过程。一名优秀的程序员决不会认为自己足够好了,不需要再提高了。自满自足的人不会是好程序员,会很快落后以致落伍。所以越是优秀的程序员越是感觉自己懂得少,不会在人前故意卖弄,这并不是故作谦虚,而是实实在在的感受,亲自体会才能明白。

  浮华的程序员会不懂装懂,不停的强调语言的优劣,平台的好坏。追求所谓最新最时尚的技术,停留在表面问题上。或假做深沉,用不适合的方式做不适合的事情。就像孔已己一样,以为知道"茴"字有四种写法就是学问。最后是简单的作不好,困难的也作不好。

三忌:死气沉沉,不求甚解

  优秀的程序员是充满激情和活力的程序员。求知欲和创造欲是原动力。有求知欲你才能不停的学习,有创造欲你才能不停的超越自己。死气沉沉的程序员已经对程序设计失去了兴趣,很快就会主动或被迫离开。

  创造不是指你要发明什么别人不知道的技术或方法,而是说不能仅仅知道怎么做,还要知道为什么这样做。之后你才能创造,其实程序设计的整个过程就是创造的过程。

四忌:强调客观,忽略自身

  很多程序员都是在失败的时候强调客观因素,而优秀的程序员的程序员都是先反省自己。要明白自己缺陷,再努力去学习。没有人事事都做的成功,也没有人生来就什么会做。所以失败了,多想想自身的原因,这样你才会不停的进步,而不是留在原地抱怨。

2007年3月6日星期二

传统之大略——《我的哲学之路》笔录

   该书概况了汤一介教授的哲学研究心得,可视为一本精湛的传统哲学入门随笔。如果于丹教授的“心得”可给我以传统经典的现代解读的话,那么这本书则从宏观的角度给我以传统哲学体系大体架构。
   汤教授将中国传统哲学的理论体系梳理为三个层次:普遍和谐观念——宇宙人生论;内在超越精神——境界修养论;内圣外王之道——政治教化论。其中所蕴含的古 代朴素辨证法都是从日常生活经验中得来的。汤教授认为普遍和谐是:自然的和谐,人与自然的和谐,人与人的和谐(社会生活的和谐)以及人自我身心内外的和 谐。而中国哲学(包括儒家、道家和中国化的佛教)与西方哲学最大的不同是它是以“内在超越”为特征的;其价值在于把“人”看成是具有超越自我和世俗限制能 力的主体。如此通观古今,为当代之大家。
   汤教授如是研究传统哲学的目的在于将其有价思想元素应用于现代社会。他认为哲学是文化的核心,深刻地反映着一个时代的精神面貌。所以研究并提炼哲学观念可 以总结人类社会文化精华。虽然汤教授认为:自古以来,我们的社会是一个以家族为本位的农业宗法专制社会,这种社会是缺乏开拓性的,比较注重守成,因此不大 注意向外输出自己的文化,在制度和观念上都压制着开拓精神,但他提出:“己所不欲,勿施于人”是可以为不同文化传统的民族和国家所共同接受的伦理准则;他 提倡“和而不同”,其意思是要承认“不同”,在“不同”基础之上形成的“和”(“和谐”或“融合”),才能使事物得到发展;从人类社会发展到今天看,任何 文化不受外来文化的影响是不可能的,也是不可取的。但是只有充分发挥其原有文化的内涵精神,才可以更好地吸收外来文化以滋养本土文化。由此看来汤教授是主 张一种“包容”的“拿来观”与“弘扬”的“送去观”,这比较现在许多困守故纸堆的“保守派学者”要开明许多。

2007年2月27日星期二

ADSL MODEM 设置

今天回来发现无法上 ADSL,打 10000 号咨询后解决了。方案记录如下:
1. 故障表现为 ADSL MODEM 的 ADSL 灯不亮, ISP 技术工程师重新刷新电信端口。
2. 在刷新端口后故障仍未解决。技术工程师问我是否重新启动过该 MODEM,这样
会造成该 MODEM 的工作模式与网络设置不匹配。需要重新设置 MODEM 模式。
(1) 将本机 IP 设置为 192.168.1.11 ,网关设为 192.168.1.1
(2) IE 登录 192.168.1. 1,修改"基本设置-ADSL模式"为 标准 " G.dmt"模
式。保存后,系统会提示"重启"。用软件重启该 MODEM 。
3. 原因是:该 MODEM 长期不用,造成端口无法与远程计算机进行同步操作,且在
本网络中只能使用 G.dmt 模式。

2007年2月25日星期日

EPS图片绘制与转换

在 Latex 中, EPS 是最常用的图片格式。但由于我最常用的 Visio 不支持
EPS 输出,所以我要重新寻找合适的 EPS 图片绘制与转换工具 。

【绘制】
Metapost 和 Asymptote : Metapost 是 Latex 平台使用最广泛的图片绘制环
境,其语法还是很容易学习的。但在 CTex 套件中的 Metapost 在 WinXP2 平台下
编译似乎并不好,有时会出错。所以我最常用的绘制环境是 Asymptote, 其优点
是编译稳定,且是类 C 语法,对于程序员更容易上手。但其支持文档很少,其帮
助文件中对于支持包的解释更少,常常需要直接阅读 asy 代码。

【转换】
(1) bmeps: CTex 套件中这个工具可以将 JPG/TIFF/PNG 格式的图片转换到
EPS 格式。由于在编译 Latex 之前总要进行对应的转换,可以用下面的 Windows
命令行来批处理(保存在 BAT 文件中运行)。
for %%f in (*.jpg) do D:\CTeX\texmf\miktex\bin\bmeps.exe -c -t jpg %%f
%%~nf.eps
for %%f in (*.png) do D:\CTeX\texmf\miktex\bin\bmeps.exe -c -t png %%f
%%~nf.eps
for %%f in (*.tiff) do D:\CTeX\texmf\miktex\bin\bmeps.exe -c -t tiff
%%f %%~nf.eps
(2) 我使用了 eps2png(linux)、AdvanceBatchConverter(Windows)和
ReaConvert(Windows)这三个软件来进行 EPS 到 JPG/PNG 格式的转换,但效果
都不是很好,会出现锯齿感。

【数据可视化】
gnuplot:在编写 Latex 文件中,常要将一些数据进行图表化。我以前的方法
是在 Excel 中导入数据绘制图表,然后导出为 JPG 文件,再转换为 EPS 格式。
如果遇到大规模数据则在 Matlab 中编写个小程序来绘制。现在看来这都是很"笨
拙"的方法。现在我使用 gnuplot 来进行数据绘制,该软件是一个数据绘制环境,
可以对数据进行2D/3D绘制,并提供多种图片格式输出(如JPG/EPS),甚至可直接
输出 Latex/Metapost等代码。

2007年2月24日星期六

Delphi中的UI组件控制

Delphi的VCL设计精妙,给现代许多Framework提供了良好的基础与开发思路。在
Delphi中,继承自TControl的UI组件可以在运行期进行遍历并能够修改其属性。比
如常见的选择框样例,某个选择框的点选决定了一个GroupBox中多个组件的状态。
我写了一个简单的Delphi函数来完成这个功能。
unit FuncComponentDisplay;

interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
ComCtrls, StdCtrls, ExtCtrls;


procedure SwitchGroupBoxState(CheckBox: TCheckBox; ParentObj: TControl );

implementation

{ TComponentDisplay }

procedure ChangeEditDisplay(aEdit: TEdit;
State: Boolean);
begin
aEdit.Enabled := State;
if State then begin
aEdit.Color := clWindow;
end
else begin
aEdit.Color := clBtnFace;
end;
end;

procedure ChangeButtonDisplay( aButton:TButton; State:Boolean );
begin
aButton.Enabled := State;
end;

procedure ChangeCheckBoxDisplay( aCheckBox:TCheckBox; State:Boolean );
begin
aCheckBox.Enabled := State;
end;

procedure ChangeRadioButtonDisplay( aRadioButton:TRadioButton;
State:Boolean );
begin
aRadioButton.Enabled := State;
end;

procedure ChangeProgressBarDisplay( aProgressBar:TProgressBar;
State:Boolean );
begin
aProgressBar.Enabled := State;
end;

procedure ChangeTrackBarDisplay( aTrackBar:TTrackBar; State:Boolean );
begin
aTrackBar.Enabled := State;
end;

procedure ChangeListBoxDisplay( aListBox:TListBox; State:Boolean );
begin
aListBox.Enabled := State;
if State then begin
aListBox.Color := clWindow;
end
else begin
aListBox.Color := clBtnFace;
end;
end;
procedure ChangeComboBoxDisplay( aComboBox:TComboBox; State:Boolean );
begin
aComboBox.Enabled := State;
end;

procedure ChangeMemoDisplay( aMemo:TMemo; State:Boolean );
begin
aMemo.Enabled := State;
if State then begin
aMemo.Color := clWindow;
end
else begin
aMemo.Color := clBtnFace;
end;
end;

procedure SwitchGroupBoxState(CheckBox: TCheckBox; ParentObj: TControl );
var
I: Integer;
TempObj : TComponent;
begin
for I := 0 to CheckBox.Owner.ComponentCount - 1 do begin // Iterate
TempObj := CheckBox.Owner.Components[I] ;
if (TempObj is TControl) then begin
if (TempObj as TControl).Parent = ParentObj then begin
if ( TempObj is TEdit ) then begin // TEdit State Switch
ChangeEditDisplay( (TempObj as TEdit), CheckBox.Checked );
continue;
end;
if ( TempObj is TButton ) then begin
ChangeButtonDisplay( (TempObj as TButton), CheckBox.Checked );
end;
if ( TempObj is TCheckBox ) then begin
ChangeCheckBoxDisplay( (TempObj as TCheckBox), CheckBox.Checked );
continue;
end;
if ( TempObj is TRadioButton ) then begin
ChangeRadioButtonDisplay( (TempObj as TRadioButton),
CheckBox.Checked);
continue;
end;
if ( TempObj is TProgressBar ) then begin
ChangeProgressBarDisplay( (TempObj as TProgressBar),
CheckBox.Checked);
continue;
end;
if ( TempObj is TTrackBar ) then begin
ChangeTrackBarDisplay( (TempObj as TTrackBar), CheckBox.Checked);
continue;
end;
if ( TempObj is TListBox ) then begin
ChangeListBoxDisplay( (TempObj as TListBox), CheckBox.Checked);
continue;
end;
if ( TempObj is TComboBox ) then begin
ChangeComboBoxDisplay( (TempObj as TComboBox), CheckBox.Checked);
continue;
end;
if ( TempObj is TMemo ) then begin
ChangeMemoDisplay( (TempObj as TMemo), CheckBox.Checked);
continue;
end;
end;
end;
end; // for
ParentObj.Enabled := CheckBox.Checked ;
end;

end.

其调用方法是:


procedure TForm1.CheckBox1Click(Sender: TObject);
begin
SwitchGroupBoxState( ( Sender as TCheckBox ), GroupBox1 );
end;

2007年2月2日星期五

为何不去作文章?

    要写论文了。但我的指尖总在写就的论文大纲晃动。为什么呢?因为我想要一个合乎性情的写作方案。何也?就是可以将科学论文、数学公式、程序代码、工作小 记、思想片段等一系列的元素组织在一个简单的系统中,并能快速地进行打印、电子邮件与博客发布。这样我就可以放开自己的思绪,按照"非线性"的方法进行论 文编写与思想记录了。
    首先我排除了 Word ,虽然其是许多人管理发布文档的"标准手段",我却不欣赏。Word 在编辑数学公式与版式设计上是如此的繁琐,而且由于 DOC 文件是二进制文件,其不能用 CVS 来进行版本管理与文本比对,实在不适合进行多个文档的长期的交叉式的编辑。这时 Latex 进入我的学习视线。 Latex 是采用标识语法符号来进行排版,其类似于程序编写,很适合我;而且其是文本编辑,可以进行 CVS 版本管理。优点多多,而且在不断地使用中会有更深刻的认知与更高明的技巧,实在是"可玩"的文档排版方案。所以我对 Latex 进行 了近2个月的系统学习,有些"玩物丧志"了。
    但这至多解决了文档排版的问题,如何记录自己思想的点滴,并能进行方便地汇总呢?我尝试了几种方案:一是用 DiaryOne 电 子笔记本进行记录。 DiaryOne 笔记本很方便,而且可以添加附件与录音。但其在信息组织上很是简陋,只能按目录进行存放,不适合多线交叉管理。然后我又用了 Wiki Wiki 是一种非常利于进行非线性编辑的工具,其可以将所写文档以链接的方式进行交叉管理;由于我多是用来记录文本,所以在尝试了一些需要安装或需要 PHP 支持的 Wiki 程序后,最后确定使用 TiddlyWiki ——这个单文件的 Wiki 作为记录之用。很神奇的一个小软件,将 JavaScript 显示技巧应用得很出色。我建议每个学习使用 Wiki 的人最好从 TiddlyWiki 开始。要使用好这个软件,应安装 Firefox,否则无法实现其强大的信息管理功 能。但可惜的是 TiddlyWiki 不支持附件,这给我带来太多的困扰。思量很久,终放弃。随后我将目光转动近年来如火如荼的 Blog 上。虽然我有许多的 Blog ,但使用率并不高,主要原因是其需要太多的 Web 编辑时间,而只有 MSNSpaceBlogger 支持我最喜爱的电邮发布。 MSNSpace 虽然是个很好的 Blog 系统,但其最大的问题是访问速度。可能 MS 将其与操作系统捆绑太多,或是国内访问较慢,每次我登录它都要等待很长时间。而 Blogger 的国内访问以前一直不稳定,我申请后就未认真打理。但这次我重新评估 Blogger ,不仅它的 beta 字样消失了,而且其在国内访问速度很快,与 GoogleGmailDoc 等结合的更好。在新版本中 Blogger 提供了全方位的模板代码编辑与电邮输入输出功能,这强烈地吸引了我。我手写了模板 CSS 代码,并且定义了电邮发布与电邮输出,从而可以同步更新 BloggerMSNSpace ,这是太好了。经过上面的一番探索,我决定采用 Email 的方式来发布 Blog 。利用 Blog 的 TAG 功能来组织自己的思想片段。
    在 Windows 平台上最常用的电邮工具是 OutLook 。虽然它很好用,但我仍不满意,因为它不支持 HTML 代码输入,就是不能在编写 HTML 邮件正文中直接插入 HTML 代码。于是我想到 Foxmail,它曾是我经常使用的电邮工具。我下载了最新版的 Foxmail 6,可惜它也不支 持 HTML 代码直接插入功能。最后我发现 Firefox 阵营的 Thunderbird ,它虽然没有 Firefox 那样有名,但其品质却很出众。不仅有强大的自定义的 Filter 功能,而且支持 HTML 代码插入。更出色的是它也是基于 Add-On 的,可以从网上下载许多有用的小插件,自己也可以编写一个。我下载了一个 pasteCode 的插件,其可以在粘贴 C、C+ +、Java 代码时自动为关键字等加上高亮颜色,很有趣。
   "磨刀不误砍柴工",通过前面的探索,现在我对自己的这一系列编辑方案进行总结,就是 Thunderbird + Gmail + Blogger + Latex(CTex) + Editplus 。其间的交流与联动,我写了一些 Python 小程序来完成。对于流程图,我试用了不少工具,但目前看来还是 MSVisio 最好,只是一想到它竟然不能发布为 EPS 格式就很切齿。

BCB中的计时与显示

在程序开发中常要实现计时与计时显示。在BCB中一般方式是利用Timer控件来进行计时。样例代码如下:
void __fastcall TForm1::Timer1Timer(TObject *Sender) {
    // timer interval callback function
    iTimerCount ++ ;
    if ( iTimerCount > 1000 ) { Timer1->Enabled = false; }
}
但Timer控件有两个缺陷:
(1)其不是一个精确的计时器,其只能保证秒级的精确性,即只有设置其Interval属性为1000的倍数是才是比较准确的。
(2)其运行级别很低,这样在多线程程序中会造成高级别线程堵塞了Timer线程从而造成计时不准确。
认识到以上两点,可将Timer控件只作为时间显示来用,而不作为计时,在每次显示时获取当前时间,并用MilliSecondsBetween函数与开始计时时间进行比较,得到毫秒级的差值,然后进行格式化显示。
样例代码如下:
(1)开始计时代码:
  iTimerCount = 0;
  startTime = Time();//< startTime 是一个 TDataTime 变量
(2)计时代码:
  void __fastcall TFrmMain::Timer1Timer(TObject *Sender) {
    // timer interval callback function
    double msValue = MilliSecondsBetween( Time(),startTime );
    Label5->Caption = AnsiString( msValue / 1000.0 );
    iTimerCount ++ ;
    if ( iTimerCount > 1000 ) { Timer1->Enabled = false; }
}
 

2007年1月30日星期二

“博客园”技术博客转移成功!

今天我将原来在"博客园"中的技术博客进行整理,转移到Google的Blogger中,以便更方便地用Gmail来发布与管理博客。

牵模式的手——《模式的乐趣》阅读笔记

很显然,从一开始我并未想到这样薄薄的一本书竟然配我走过两个多月的时光,而且让我时时激起购买它的欲望(现在我还是遵循"书非借不能读"的古训)。想起那天和Decland谈起《DesignPattern》,他感慨于该书Scholar气息太浓,Sample太少。现在我也有同感了。的确《DesignPattern》太过于严谨,对于OO的新手来说缺少亲近它的欲望。而这本小册子,则很能成为阅读《DesignPattern》的辅助读物,像筵席外的一份零食。
"简而言之,模式也是世界上出现的一种事物,其规则告诉我们如何创建这种事物,以及何时必须创建它。它既是过程,也是事物;既是对存在的事物的描述,也是对创建这种事物的过程的描述。——Alexander[1979]"
"对于软件来说,算法、数据结构是基本构件,模式也是,甚至更像是定义算法和数据结构的模具"
"模式的一个主要目标就是,以一种别人容易接受的方式,捕捉那些重复出现的问题的解决方案(以及可以使用这些解决方案的约束和场景)",从语义表达角度,模式所能传达的信息更多,更精密。这也是其难于掌握的原因。像情侣间一个细微的眼神,如果没有日日夜夜的厮守,是无法达到的。
"每一种模式都应该是对其他模式的补充。每增加一种模式都应该让系统更加强壮。这样的系统可以不断发展,且不会增加维护的压力,也不会降低整个系统的性能——系统增大后通常会导致这种结果。我们希望创建一个各部分互为补充的框架,希望每一个新增的部分都能让其他部分更加强壮"
"模式不会存在于真空中。实际上,模式不仅依赖于其自身,而且依赖于整个体系结构中所有其他模式。每种模式本身都由相互依赖的其他成分组成"。模式更像软件的社会化属性,在良好模式设计的系统中,众多简单对象合同协作,完成复杂任务。可见,模式可以由人的管理模式进行映射。善于了解模式的人一定也是善于发现社会协同机制的人。
"没有经验的开发人员常常不理解设计与实现之间的区别,所以这些习惯语法就成了他们表达设计思想的唯一途径""如果你唯一的工具是锤子,你就会把所有的东西都当作钉子"
"模式是不依赖于编程语言的(与之相反的习惯语法是编程语言特有的)。从某种程度上讲,模式构成了一种语言,它比编程语言更进了一步,使开发人员可以彼此交流设计思想。……模式本身超越了任何具体的语言,这绝不是要忽视选择编程语言的重要性,只是希望你认识到,编程语言不应该限制我们提供有价值的技术的能力"
"当一个人从事设计活动时,他的行为完全受当时他心中已有模式语言的支配。当然,随着经验的增长,每个人心目中的模式语言都会随着时间而变化。但是,在必须做出设计决定的那个特定时刻,他要完全依赖在此之前他已经积累的模式语言。不论他的设计多么小或多么复杂,他的设计活动将完全受他心目中已有的模式以及他将这些模式组合新的设计的能力的支配——Alexander[1979]"

有知者无畏!-读《与熊共舞》

当我合上这本书的黑色封面的时候,不由想起《老人与海》中的那句名言:人不是生来就被打败的。的确,在这本书中,洋溢着一种人类理性无比的自信。不是吗?
风险管理,在许多人看来,是如此虚无缥缈的东西,人们似乎无法完整地定义风险,也无法确切地预知未来。在风险的面前,除了迷惘与祈求,大多数时候总会如鸵鸟一样将头埋在沙中,欺骗自己没有看到风险。但作者却没有这样,他在最艰涩的地方开凿,在最朦胧的地方勾绘蓝图。虽然我还不能完全理解那些曲线间的确切含义,但我明了在这些曲线的后面是一颗充满理性与必胜信念的心。
其实不仅在软件界有风险管理,在其他领域,甚至于在生活的方方面面都应存在如是的"管理"。在问题面前不回避,在挫折面前不动摇,用理性的力量与经验的承继去解决它们。这是一种伟大的性格,一种光辉的精神。
[写此篇以自励]

在脚边的程序段

这几日总是为Floater菜单的不运行而烦恼,因为我找不到产生错误的原因。我总是认为是脚本有误,但今天参考去年我编写的精品课程网站脚本,发现其没有什么问题。静下心来又细查了一遍,突然发现去年的网页头部没有
<!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">

突然我知道问题症结了,原来是Dreamweaver8自动设置的Web头比较严格,其阻止了浏览器解释一些特殊Javascript代码。解决很方便,只要将文件头替换掉就可以了。
现在知道要解决问题,往往不要仅关注问题本身或附近,要有抬头四顾的能力。只有这样才会在不经意间找到真正的原因。

JavaScript CodeSnippets——获取Cookie

function getCookie(Name) {
  var search = Name + "="
  var returnvalue = "";
  if (document.cookie.length > 0) {
  offset = document.cookie.indexOf(search)
  if (offset != -1) {
  offset += search.length
  end = document.cookie.indexOf(";", offset);
  if (end == -1)
  end = document.cookie.length;
  returnvalue=unescape(document.cookie.substring(offset, end))
}

用法:
if( getCookie("myCookie") ){
//Todo something
}

BCB中执行SQLServer远程存储过程

BCB中执行SQLServer的远程存储过程,应采用TADOConnection与TADOStoreProc组件组合使用。其中TADOConnection组件作为连接数据库,而TADOStoreProc组件则作为运行存储过程。
1.连接数据库
void __fastcall TDataModule::OpenADOConnection()
{
ADOConnection1->ConnectionString = "...";
ADOConnection1->LoginPrompt = false;

try
{
ADOConnection1->Connected = true;
}catch(...)
{
//TODO: Show Database Open Error Message
return;
}
return;
}

2. 设置存储过程
(1)在BCB中最好采用设计器来设置TADOStoreProc组件的存储过程名,这样可以自动将存储过程的参数添加。记得在Build前将TADOConnection的Connected设为false就可以了。
(2)在运行期采用Parameters属性来设置存储过程参数
StoredProc1->Close();
StoredProc1->ParamByName("@ParaID")->AsString = edtID->Text;
//其它参数

(3)采用ExecProc方法或Open方式运行存储过程
if(!StoreProc1->Prepared)
StoreProc1->Prepare();
StoreProc1->ExecProc();

(4)最后可以通过参数或者TDataset来获取结果
Label1->Caption = StoreProc1->ParamByName("@ReturnValue")->AsString;

SQL Server安装文件挂起错误解决办法【转帖】

现象:
安装SQL Server的时候,系统提示。"以前的某个程序安装已在安装计算机上创建挂起的文件操作。运行安装程序之前必须重新启动计算机。" ,但是重启依旧不能解决。
解决:
打开注册表编辑器,在
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\ Control\ Session Manager
中找到PendingFileRenameOperations项目,并删除它。这样就可以清除安装暂挂项目。

AccessSQL语句中的时间处理

在Access中如果要比较日期,应该用DateValue函数来进行格式归一化。比如:
delete from sf_guestonline where lastactivity < DateValue('2006-9-24 下午 01:46:16')
在雪人论坛(access)版中存在用#来标示时间的用法,由于Access驱动的问题,在一些机器上(比如我的)就不能用,所以应该采用DateValue函数的方式。

Linux环境下可视化开发[翻译]

原文:Visual Development on Linux
http://openubuntu.blogspot.com/2006/11/visual-development-of-linux.html
对于许多比较依赖鼠标的人来说,印象中Linux下开发不是件容易事。如果你乐于命令行则另当别论。现在你有了选择。已经有一大堆的Linux可视化开发环境等着你用呐!下面我来介绍几款....(此处省略原文N个词,老外就是啰嗦呀)

1.NetBeans
一个JAVA开发环境!作为一个玩JAVA的,你不一会儿就会爱上她!wo!拖拖拉拉就完成一个程序啦!
她支持:
一般的Java程序或库开发
Web程序开发
EJB开发
WebService、WebService客户端
J2ME MIDP程序
JAVA图形化用户界面开发
NetBeans 插件

2.QT/KDevelip Desinger
QT是KDE上最好的开发环境,其也可用于Gnome。只要托拖拽拽就可以完成一个数据驱动的C++程序咯{译者注:KDevelop更好用一些,我在Rethat Enterprise 环境的C++开发都用KDevelop}

3.Gambas
一个VisualBasic的克隆。对于要转入Linux的VB程序员是非常有用的哟!美观简捷的界面,可通过Gambas方便地连接主流数据库(MySQL,PostgreSQL等)

4.NVU
一个取代Macromedia产品的网页编辑器。WYSIWYG,且可直接FTP到你的网站

5.Eric
一个简便高效的PythonIDE哟!

6.Eclipse
最流行的开源开发环境{译者注:这个就不用再说啦,网上连篇累牍}

7.JDeveloper
一个免费非开源的Java编辑环境,可以像VB/Delphi一样开发Java程序。其来源自Oracle,JDeveloper使用Sun的JDK。

8.Planner
一个类似Project的项目管理软件,可以轻松绘制甘特图。

9.RealBasic
一个商业的IDE。可以像VB一样的开发。

10.IntellijIDEA 6.0
一个开发Java的商业环境

{译者注:我在Linux下一般就使用KDevelop和Eclipse就可以了,当然KEdit、Vim和Emacs也是常用的编辑器,但不能可视化开发。毕竟Linux不是Windows,操控性比可视化更重要!不是吗?}

《Win32多线程程序设计》笔录

读后感:

这本书是一本Win32下多线程的抗鼎之作,其涵盖了多线程编程的方方面面。我阅读的原因在于期望能了解原汁原味的Win32下多线程编程。而我以前只是使用BCB的TThread等对象进行Win32多线程快速开发。阅读后的确对于Win32下的许多概念清楚明了不少,但也产生许多新的疑问。但我知道,这些疑问许多并不能在这本书中获得求解。在.Net下的Windows多线程开发已经有了新的发展,需要我继续努力学习。
我以前对侯捷老师的译注总有些不适应,总感觉侯老师严谨有余,亲和力不足。但这本书中,侯老师的精彩译注,以及对于原著错误的指正,使我的阅读受益匪浅。我才真正感受到严谨的魅力。感谢侯老师。
下面是我的笔录,其中{}为我的随感。

笔录:

P4
多线程,使程序得以将其工作分开,独立运作,不互相影响

P12
线程廉价:线程启动快,退出快,对系统资源冲击小,且线程彼此分享了大部分核心对象的拥有权。

P26
WinBASE.H -->CreateThread 产生一个线程

P33
1.多线程程序无法预期-->掌握多线程程序的预期是一项很高级的分析编程能力
2.执行次序无法保证
3.线程对于小的改变有高度的敏感-->调试器会引入不确定
4.线程并不是立刻启动
5.线程上的资源泄露更常见且更致命的
CloseHandle释放核心对象;GetExitCodeThread 线程结束代码;
ExitThread 强制结束线程

P47
主线程:Primary Thread
1.负责 GUI(Graphic User Interface)
2.该线程结束会使其它线程强迫结束、无从清理;

P48
经验显示,线程的各种相关函数是错误高危险群,而适当的错误处理可以阻止挫败并产生一个比较可信赖的程序;

P51
Microsoft Threading Model --> GUI Thread、Worker Thread

P53
设计目标:简单和安全、更甚于复杂和速度;
在线程之间以最低表面积来设计程序;
[最低表面积:线程共享的数据结构]

P59
成功秘诀:
1.各线程的数据要分离开来,避免使用全局变量;
2.不要在线程之间共享GDI对象;
3.确定你知道你的线程状态,不要径自结束程序而不等待它们的结束;
4.让主线程处理用户界面(GUI)

P62
绝不要在Win32中使用BusyLoop;
[应该用WaitForMultipleObjects\MsgWaitForMultipleObjects]
[控制自由触发Event为非自由触发Event,这样可以来避免系统的死锁]

P75
Unix的Signal-->立即的消息信号,有冲击
Windows Signaled Object -->内部状态的改变,无冲击

P94
在Windows系统中:PostMessage() 异步 并行;SendMessage() 同步 串行

P95
最容易的同步机制:Critical Sections
InitializeCritical Section \ DeleteCriticalSection \ EnterCriticalSection \ LeaveCriticalSection
[EnterCriticalSection 可嵌套]
[加上CriticalSection保护后可以实现数据操作的"原子化"]

P100
不要长时间锁住一份资源;而CriticalSection是不知道线程的生死的-->Mutex(互斥器)-->WaitForMultipleObjects

P108
Mutex-->核心对象,牺牲存储保证运行稳定;可跨线程\跨进程使用;Mutex有可能被"不负责"的线程"遗弃"。
[Mutex是Windows所特有,在其它系统中则使用Semaphore{旗语}

P120
EventObject(事件)-->最具弹性的通步机制;Event的状态完全在你的控制之下;可以精确地告诉一个Event对象做什么事,以及什么时候去作;其应用于多种类型的高级IO操作中。
CreateEvent\SetEvent\ResetEvent\PulseEvent

P128
同步机制摘要*

P132
TerminateThread -->放弃一个线程-->最糟糕的想法,永远不要这么用。

P135
Windows中终结Thread的标准操作方式:建立一个Event对象来自检Thread消亡,即周期性地检查一个Event对象,以决定要不要结束自己。

P140
优先级:线程的社会阶层

P157
Overlapped IO是一个高层技术:Windows给于我们具有Thread能力的IO函数

P198
要加上Volatile量来表明其在多线程下不能被编译器错误优化。
{对单线程有效优化对于多线程常带来BUG}

P200
{引入数据库的Transaction(事务)来解决多线程的数据一致性问题}
{侯捷先生的译著中这样的拓展译注很有用,且尊重出处,当效之}

P204
{在不考虑效率下,将锁定范围扩大会解决很多棘手问题。如将一个树型数据集根点锁定以避免其它线程的非法操作}-->排他锁定

P215
{作者给出一个Read/Write锁定方案,没看懂}
Fine Granularity{逐个锁}:很容易产生死锁、效率瓶颈的情况尚可令人放心、"锁定"所花费的时间可能招致高度浪费。 Coarse Granularity{全部锁}:使用简单、死锁风险极低、容易产生效率瓶颈。两者都是十分极端的。

P260
一个非静态的类成员函数都有一个隐藏起来的参数被推入堆栈中,当编译器需要处理类的成员变量时,它需要这个隐藏参数的帮助,这就是"this"参数(一个指针)

P261
为了以一个成员函数启动一个线程,要么你就使用静态成员函数,要么你就得使用C函数(而非C++成员函数)

P274
异常情况处理机制的好处在于,它在标准函数调用和返回(Call/Return)模式之外运作。

P277
如果要在MFC程序中产生一个线程,而该线程将调用MFC函数或使用MFC的任何数据,那么你必须以AfxBeginThread或CWinThread::CreateThread来产生这些代码

P278
面对Windows程序设计中的线程,有下列三种层次:
1.Win32API CreateThread() EndThread()
2.C Runtime Library _beginthreadex() _endthreadex()
3.MFC AfxBeginThread() {MFC方式封装了上述两种方法}

P286
{MFC给我们作了许多封装,在该页给出一个NakedVersion来说明封装细节}

P294
你不能放一个指针(指向一个CWnd)到结构中。而该结构被一个Worker线程使用。你也不能把一个指向CDialog或CView的指针交给另一个线程
{这是享受MFC方便同时的代价}

P300
虽然MFC的同步控制类对于基本结构的锁定很有帮助,但它们面对比较复杂的工作时却黯然失色。{这是享受MFC方便同时的代价}

P304
所有传送给某一个窗口之消息,将由产生该窗口之线程负责处理。{这是一条设计原则,这样可以使UI设计更清晰}

P311
欲在一个MDI程序中有效率地使用多个线程,我的建议是以一个线程处理所有的用户输入,以及所有用户界面的管理,然后使用一个以上的线程来负责诸如重绘、打印等工作。......你的主线程(负责主框架窗口)总是应该能够有所回应,不会陷入长时间计算的泥沼中。

P318
所有这些问题或许都可以绕道解决。但很明显我正在强迫系统做一些它并没有被设计那么做的事情。我越是想办法挖东墙补西墙,整个机制就越是变得脆而虚弱。......这个例子提醒我不适当使用线程所带来的危险。不幸的是,在"适当使用"与"不适当使用"之间,界限模糊。
{清楚了解系统内部机制是很重要的。不要用蛮力,要从内部挖掘,攻"心"为上}

P321
对于一个多线程程序调试,如果没有经过小心的策划,很可能就像抓蝴蝶一样。你可以看到问题,接近它,但是当你几乎已经就要用手抓着它时,它飞走了,然后在另一个地方出现。

P325
运转记录:程序全身插满printf();{要注意I/O是很慢的操作,这样就会对程序本身有冲击}

P336
进程可用来作为"隔板"机制。这有点像船舱被分割为防水壁和许多船壳一样。利用不同的进程所产生出来的边界,可以阻止错误到处蔓延。

P336
在同一进程的不同线程之间搬移数据,最简单的一种做法就是利用消息队列。......Windows定义了一个消息,名为 WM_COPYDATA,专门用来在线程之间搬移数据--不管两个线程是否同属一个进程,和其它所有的消息一样,你必须指定一个窗口,也就是一个 HWnd,当作消息的目的地。所以接受此消息的线程必须有一个窗口(译注:也就是它必须是个UI线程)

P339
进入C++世界,情况又更复杂些了,绝不可以把"指向某个拥有虚函数的对象"的指针当作lpData来传递{这样就很麻烦了,因为在MFC中,由于继承,多数对象都具有virtual的析构函数,如CString。这样就无法直接使用它们作为WM_COPYDATA的传递参数来在进程间传递数据。如此看来WM_COPYDATA局限性很大,是"戴着脚镣跳舞"呀}

P344
WM_COPYDATA是唯一一个可以在16位程序和32位程序之间搬移数据的方法;但其效率低,不能传递给没有窗体的线程,不支持PostThreadMessage

P345
Win32的一个基础观念就是,进程之间要有严密的保护。每一个进程认为它拥有整部机器,从一个进程中要看到另一个进程的地址空间的任何一部分,都是不可能的。

P346
所谓共享内存,是一块在设计时即打算给一个以上的进程在同一时间都看到的内存区域。

P346
设定一个共享内存区域(Shared Memory Area)需要两个步骤:
(1)产生一个所谓的file-mapping核心对象,并指定共享区域的大小-->CreateFileMapping
(2)将共享区域映射到你的进程的地址空间中。-->MapViewofFile/UnmapViewofFile-->OpenFileMapping/CloseHandle

P354
任何Collection Class(译注:用于array、list、map之C++类),不论来自MFC或其它地方,都不能够安全地使用于共享内存中。

P361
使用共享内存不是件容易的事{对于多线程,也是一样}

Delphi开启Windows目录对话框代码

今天整理以往的项目代码,发现自己以前在网上找到的一段Delphi开启Windows目录对话框的代码,觉得对许多Delphi初学者很有用,特转贴出来。由于时间过久已经无法知道是从什么地方摘录的,在此特向原作者表示感谢!

Windows目录对话框是一个标准的WindowsUI控件,其可以列出一个目录列表,并且可以显示新增按钮。由于Delphi中并没有提供对于该控件的封装,所以新手(包括当年的我)大多使用Win31目录下的DriverList、DirectoryList、FileList和 FileFilterList四个控件进行组合来获取当前目录,这样操作复杂且不美观。有的高手可以直接用WindowsAPI调用Windows目录对话框,但我确直到找到该段代码前还是使用最原始的方法{叹自己的懒惰呀!}

该段代码分为两个部分:(1)控件代码 (2)调用代码
(1)控件代码:由于该控件没有封装成Delphi控件格式,其使用方法有些原始,就是将它的源文件BrowseForFolderU.pas复制到当前项目目录并添加到当前项目中。代码如下{是别人高手写的,致敬呀......}
unit BrowseForFolderU;

interface
function BrowseForFolder(const browseTitle: String;
const initialFolder: String = ''): String;

implementation
uses Windows, shlobj;
var
lg_StartFolder: String;

///////////////////////////////////////////////////////////////////
// Call back function used to set the initial browse directory.
///////////////////////////////////////////////////////////////////
function BrowseForFolderCallBack(Wnd: HWND; uMsg: UINT;
lParam, lpData: LPARAM): Integer stdcall;
begin
if uMsg = BFFM_INITIALIZED then
SendMessage(Wnd,BFFM_SETSELECTION,1,Integer(@lg_StartFolder[1]));
result := 0;
end;

///////////////////////////////////////////////////////////////////
// This function allows the user to browse for a folder
//
// Arguments:-
// browseTitle : The title to display on the browse dialog.
// initialFolder : Optional argument. Use to specify the folder
// initially selected when the dialog opens.
//
// Returns: The empty string if no folder was selected ( i.e. if the
// user clicked cancel), otherwise the full folder path.
///////////////////////////////////////////////////////////////////
function BrowseForFolder(const browseTitle: String;
const initialFolder: String =''): String;
const
BIF_NEWDIALOGSTYLE = $40;
var
browse_info: TBrowseInfo;
folder: array[0..MAX_PATH] of char;
find_context: PItemIDList;
begin
FillChar(browse_info,SizeOf(browse_info),#0);
lg_StartFolder := initialFolder;
browse_info.pszDisplayName := @folder[0];
browse_info.lpszTitle := PChar(browseTitle);
browse_info.ulFlags := BIF_RETURNONLYFSDIRS or BIF_NEWDIALOGSTYLE;
if initialFolder <> '' then
browse_info.lpfn := BrowseForFolderCallBack;
find_context := SHBrowseForFolder(browse_info);
if Assigned(find_context) then
begin
if SHGetPathFromIDList(find_context,folder) then
result := folder
else
result := '';
GlobalFreePtr(find_context);
end
else
result := '';
end;

end.

(2)调用代码:和一般函数调用很类似。先在调用窗口pas文件前引用一下该控件文件
uses
 BrowseForFolderU;
然后是"八股"代码
procedure TForm1.BtnSampleExecute(Sender: TObject); //演示按钮Click事件函数
var
oPath,oPath1,outMsg:String;
begin
oPath1 := 'c:\';//目录对话框的初始目录
outMsg := 'Windows目录对话框演示';//目录对话框上显示的提示信息
oPath := BrowseForFolder(outMsg,oPath1);//启动Windows目录对话框,一句话就解决了。
if oPath = '' then //如果返回地址为空,则报错
begin
outMsg := '你没有选取任何目录!';
Application.MessageBox(PChar(outMsg),'WARNING',0);
Exit;
end;
else //否则由oPath中提取选取目录地址,进行操作
begin
   //你的操作代码
end;
end;

就这么简单咯,希望能给Delphi初学者一点帮助。

Delphi中使用JPEG图片

这是个"过期"技术问题,我仅作为存档贴出来。以备日后参考。
Delphi中读取JPEG图片可使用TJPEGImage对象,样例代码如下:
var
   jpeg :TJpegImage ;
begin
   jpeg := TJPEGImage.Create;
   try
    jpeg.LoadFromFile(FileName);
    Image1.Canvas.Draw (0,0,jpeg);
   finally
    jpeg.Free;
   end;
end

Delphi中压缩文件

Delphi中压缩文件的最好方式是使用ZipTV控件。其样例代码如下:
procedure TForm1.Button1Click(Sender: TObject);
var
  FileCompressed,I: Integer;
  FileName:String;
begin
  if SaveDialog1.Execute then
  begin
    Zip1.ArchiveFile := SaveDialog1.FileName;
    Zip1.DateAttribute := daFileDate; // default value
    Zip1.StoredDirNames := sdRelative; // default value
    Zip1.CompressMethod := cmDeflate; // default value

    Zip1.FileSpec.Clear ;
    for I := 0 to ListBox1.Items.Count - 1 do // Iterate
    begin
        Zip1.FileSpec.Add(ListBox1.Items[i]);
    end; // for

    FileCompressed := Zip1.Compress;
  end;
end;

VBA小试牛刀

今天在看一本电子书《诸葛亮的十堂哲学课》时,突然想将其重新编辑成PDF格式。当我将书的第一章内容复制到Word中时才发现字符中混杂了太多的回车符。这时我想起前几天学习的VBA课程,在这里小试牛刀咯。
下面就是我写的一段VBA程序,可以将文本中的多余空行删除。其算法是逐行扫描文档,当发现该行只有一个符号(必为回车符)时就将其删除。
iCount = 0
Dim ps As Paragraph
Dim rngRange As Range
For Each ps In ActiveDocument.Paragraphs
iCount = iCount + 1
Set rngRange = ps.Range

If rngRange.Characters.Count = 1 Then
'MsgBox (rngRange.Characters(1))
rngRange.Delete
End If
Next

但我还没想出如何能删除段末尾的回车符,我不知道如何判断,虽然可以通过
If rngRange.Characters(rngRange.Characters.Count) = Chr(13) Then
来判断段落结尾处的字符是否是回车符,但如果简单删除,则会将原有的段落去除。且这样会引起循环的错误,在进行段落遍历的时候产生错误。
我想到可以用一个数组来存放单个回车符的位置,然后利用原文档中段落间有两个回车符的特点,将单回车符删除就可以了。
下面是代码,其可以在短文档中用,在长文档时还是会有数组溢出。要重新考虑算法咯。
Sub ClearBlankReturnChar()
Dim iCount, iIndex, iParagraphsNum
iCount = 0
iIndex = 0
Dim aLines(10000)

Dim ps As Paragraph
Dim rngRange As Range
For Each ps In ActiveDocument.Paragraphs
iCount = iCount + 1
Set rngRange = ps.Range
If rngRange.Characters.Count > iMaxRangeCount Then
iMaxRangeCount = rngRange.Characters.Count
End If

If rngRange.Characters.Count > 1 Then
iIndex = iIndex + 1
aLines(iIndex) = rngRange.End
End If
Next

For i = 1 To iIndex - 1
Selection.SetRange aLines(i) - i, aLines(i) - i + 1
'MsgBox (i)
Selection.Delete
Next
End Sub

夜已经很深了,早点睡咯!2006年8月13日

WindowsXP定时关机脚本

我以前写得一个脚本,每次重装机器都要用到,现贴在这里,以免下次重装要到备份光盘里找!
at 22:00 /every:m,t,w,th,f,s,su Shutdown -s -f

删除CVS版本控制目录

今天要将一个Dreamweaver制作的网站进行更新,但由于这次采用CVS来管理网站源文件,所以在系统目录中混入了许多CVS子目录。更新时因为这些细碎的文件夹造成FTP上载速度很慢,于是想到可以先复制一个目录然后采用批处理脚本删除其中所有的CVS文件夹。参考Zeali的Blog(http://www.zeali.net/entry/351 )中的BAT批处理文件,编写如下的批处理文件 ClearCVS.bat。
@echo On
@Rem 删除CVS版本控制目录
@PROMPT [Com]#
@echo Find CVS
@for /r . %%a in (.) do @if exist "%%a\CVS" @echo "%%a\CVS"
@echo Find CVS Dir....OK
@pause
@for /r . %%a in (.) do @if exist "%%a\CVS" rd /s /q "%%a\CVS"
@echo Clear CVS Dir Mission Completed
@pause


而且我发现Dreamweaver也会在站点目录中存放许多_notes目录,参考上面的脚本再编写一个新的ClearNotes.bat如下
@echo On
@Rem 删除_notes目录
@PROMPT [Com]#
@echo Find _notes
@for /r . %%a in (.) do @if exist "%%a\_notes" @echo "%%a\_notes"
@echo Check _notes Dir ....OK
@pause
@for /r . %%a in (.) do @if exist "%%a\_notes" rd /s /q "%%a\_notes"
@echo Clear _notes Dir Mission Completed
@pause


这样就可以轻松解决目录冗余的问题了。
=======================================================================
我编写了一个Python程序,也可以完成清除CVS目录的工作
# yankchina@gmail.com
# Clear CVS Folder
def ClearCVSFolder( inFolderName ):
''' Clear CVS Folder
'''

import os
for root, dirs, files in os.walk( inFolderName , topdown = False ):
for name in dirs:
cvsname = root +'\\' + name + '\\cvs\\'
if os.path.isdir( cvsname ):
os.remove( cvsname )
print 'Remove CVS DirectoryName:' + cvsname

# InputMain Function
def inputMain():
import sys
if len(sys.argv)>=2:
currentDir = sys.argv[1]
else:
print "Please Input Folder Name: "
currentDir = raw_input()
print "Clear CVS Label Folders"
ClearCVSFolder(currentDir)
print "Any Key To Return..."
currentDir = raw_input()

if __name__ == "__main__":
inputMain()

2007年1月29日星期一

微软课程学习笔记

2006 八月 05, 10:34 上午
Word下的VBA学习笔记
=======================================================================
参考陈锐《Word下的VBA开发》
=======================================================================
1.VBA简介:一个内嵌于Office的编程扩展。要了解VB/VBA/VBScript之间的关系。
2.采用MS的VBASDK可以在自己的软件中增加VBA控制。
3.最简单的VBA操作就是录制宏。在录制宏时,会"过忠实"地保留你的操作,产生大量冗余代码,这要求我们来进行一些清除工作。
4.VBA的资源以Project(工程方式)进行管理,包括模版\代码等
5.命令窗口可快速执行代码,并可以输出一些感兴趣的内容。如
?ActiveDocument.Tables.Count
可直接在命令窗口中直接输出结果
6.建立一个新的VBA可以从录制宏开始。这里可以做一个将该文件中的所有表格的第一个行进行合并,然后文本居中加粗。在录制宏后,可以立即阅读宏记录,如果遇到不能理解的对象或操作,可以用Ctrl+F1调出快捷帮助来。下面是一段样例代码:

'yankchina@gmail.com 2006-08-05
'陈锐《Word下的VBA开发》
Dim t As Table
For Each t In ActiveDocument.Tables
'循环操作表格
t.Rows(1).Cells.Merge
t.Rows(1).Cells.Range.ParagraphFormat.Alignment = wdAlignParagraphCenter
t.Rows(1).Cells(1).Range.Bold = wdToggle
Next

在VBA中点选不同的过程,即只运行该过程。
7.Word对象模型是掌握VBA操作的基本知识,而且要有OOP的知识结构。
8.在Word中创建一个Office对象,可以使用
Set olApp = CreateObject("outlook.application")
来创建,陈锐的例子都是很棒的,这个例子可以根据Word中的表格来创建Outlook联系人。我可以根据这个例子来创建一个VBA脚本,来在Word中 创建一个Outlook的联系人表。也可以在Outlook中编写VBA来自动根据Word中的表格来发送Email信息。
=======================================================================
我要收集一些自己在日常工作中的自动化需求,然后用VBA或.Net方式来编程实现
=======================================================================
《程序员2006》学习笔记
=======================================================================
这是微软WebCast上一期节目,回眸2005,展望2006。
1.微软新的认证体系
2.Microsoft网站上有一个ScoreReportAndLearningPlan,这样可用来进行个人技能检测。
3.Microsoft E-Learning 免费的培训学习资料/视频。
=======================================================================
《VisualStudioTeamSystem情景演示》学习笔记
=======================================================================
1.方法论+工具
(1)有法可依:XP、RUP、MSF...
(2)有法必依:工具:BugManagerSystem、SourceControl
(3)执法必严:集成,各种工具集成工作
(4)违法必究:企业管理制度
2.可以下载Microsoft的MSF文档来学习一些微软的项目开发经验。
3.在VSTS中有MSF的模版,这样可以自动组织到CMM3水平。这说明在微软中的软件开发系统已经是完全信息化了。(目前我看到的许多软件开发团队和开发项目其仍然是手工化管理,好奇异的事情,不自动的软件系统来创建自动项目)
4.在VSTS中用Excel来管理项目需求(Title/Kind/State/Priority),可要参考MSF文档来确定其结构。
5.将Excel需求导入Project,在Project中进行工程安排。记得上次学习Project可以直接导入Excel文件的。
6.架构师主要完成架构设计,并且应向代码设计人员下发逻辑实现。
7.项目经理可以通过VSTS来访问察看项目进度,也可以从团队网站中进行察看。
8.VisualStudio2005中的类图更契合.NET语言的特性。
9.NUnit一个成员加入MS,这样在VSTS中会生成NUnit单元测试框架。且其可以通过代码的背景来看到测试的结果,而不是某个测试函数是否测试通过(很Cool的单元测试)。
10.VSTS中可以使用Shelve方式将代码挂起在服务器端。
11.VSTS中可对代码进行统计分析。并可以通过自定义规则方式来检查团队代码的命名规则。
12.在VSTS中有LoadAndStressTest/ManualTest/UnitTest/WebTest等不同测试项目。且提供了虚拟测试环 境,这样就可以构建Win98/Win2000/WinXP等不同软硬件环境下的测试。可以方便地生成图表,找到软件BUG和瓶颈。
13.MSF4.0包含的轻快开发软件进程是我当前要学习的重点。

细线条框表格的CSS代码

今天朋友问我如何制作一个细线条框。在以前的方法是通过两个嵌套表格来实现细线条表格的制作,但这种方法与W3C网络标准不符,所以应该采用css的方法来制作单线条框。原理是利用定义对象上下左右边线,内部的单元格绘制上边和左边,外部的表格绘制下边和右边。具体CSS代码如下:
<style type="text/css">
<!--
.frameTable {
border-right-width: 1px;
border-bottom-width: 1px;
border-top-style: none;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: none;
border-right-color: #000000;
border-bottom-color: #000000;
}
.frameTable td{
border-top-style: solid;
border-top-width:1px;
border-left-width:1px;
border-top-color: #000000;
border-right-style: none;
border-left-style: solid;
border-left-color: #000000;
border-bottom-style: none;
}
-->
</style>

调用的方法如下:
<table width="900" border="0" cellspacing="0" cellpadding="0" class="frameTable">
<tr>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
</tr>
</table>