2007年11月5日星期一

vim使用技巧(2)转载

读本文之前请注意:
1. 本文的目标是提供一些vim的使用技巧,利用这些技巧可以提高vim的操作效率。部分技巧在vi上也可以使用,但是现在基本上都是用vim了。
2. 本文是整理和总结使用技巧,而非讲解vim入门,因此不会涉及最基本的使用,例如如何上移或下移光标,对此类操作请参阅任何一本vim或者vi教程。
3. 本文阅读对象是了解了vim的基本操作,而希望高效地利用vim进行工作的人。熟练使用vim的人自然不必细读,如果能留下您的宝贵意见,本人将感激不尽。
4. 本文由本人搜集整理,转载请注明出处
本文一般情况下用(里边的字母一般大小写无所谓,除非特别注明)表示按住ctrl同时按下相关
字母,命令前加一个i表示在插入模式下用这个命令
1. 选定文字 / 拷贝粘贴
v为可视模式,可以选定多行。选定多行之后,可以用yy或者dd等等进行拷贝和剪切。
p 是粘贴
y 和d 可以直接拷贝或者剪切选定的内容
yw是拷贝一个单词
如果要复制整行的最简单办法就是V,y,p 就行了
v是可以选定一行任意个字符的,V是行选定的,一次一整行,然后通过向下或向上移动光标而选定多行。
对于v选定的,拷贝后就是这么多,选多少就拷贝多少,而V选定的,粘贴的话会自动换到下一行
命令模式下,也是块选定,不过是列块选定
2. 折叠代码
可以zf进行折叠, 用zo打开折叠,也可以方向键向右打开折叠,zc 关闭折叠(只要在被折叠的块中的任一个
语句就行)

3. 缩进代码

<是左缩进, >是右缩进
按v选定后按=就是自动格式化代码,自动缩进,内部的递归的缩进都做到了
行左移<<,行右移>>,该命令用于调整源码缩进格式简便快速。

4. 移动光标
%是从大括号的开始移动到大括号的结束位置
:后边加行号就是跳到这一行
光标返回到以前的位置。相当于光标移动的“撤销”
光标返回到后来的位置。相当于光标移动的“恢复”

5. 多文件编辑 / 缓冲区命令

vim下每一个打开的文件对应一个缓冲区(buffer)。
多文件编辑会有两种情形,一种是在进入 vim 前所用的参数就是多个文件(这种情形称为 argument
list)。另一种情形是进入 vim 后另外再开其它的文件(称为 buffer list)。不过都可以统称为
buffer。
5.1 打开文件
vi flname1 flname2… flnameN
将多个文件调入缓冲,是 argument list。
:e filename
这是在进入 vim 后,在不离开 vim 的情形下再开其它文件,只要您要编辑的档案是在目前目录,Tab 补
全键还是可以使用。是buffer list。
注意::e 或者:new 或者:split 后边可以跟目录,这样就可以在目录下慢慢找要打开的文件了

5.2 缓冲区跳转
:n 编辑下一个文件。
:2n 编辑下二个文件。
:N 编辑前一个文件。注意,这种用法只能用于 argument list 的情形。
:rew 回到首文件
:args 查看当前编辑缓冲文件状态
:e# 或 Ctrl-^ 编辑前一个档案,用于两文件互相编辑时相当好用。这种用法不管是 argument list 或
buffer list 档案间皆可使用。 使用Ctrl-^ 命令更便捷,但如终端类型不正确该功能将无效。
用:ls来显示缓冲区中的文件,编号后边有#的代表是前一个文件,可以通过:e#来进入,有%a的代表是当
前文件,什么也没有的可以通过:bn来进入,这里的n代表文件编号。
:b文件名或编号 移至该文件。
在 :ls 中就会出示各文件的编号,这个编号在未离开 vim 前是不会变的。这个指令 elvis 也是可以使
用。当然 :e#编号 也是可以的,这样的用法则是所有 vi clone 都通用了。
在 buffers 中,减号 - 表示这个 buffer 并未载入,不过,不必担心,载入相当快速的。加号 + 表示
这个 buffer 已经修改过了。
:bn buffer next。这里的n代表字母n
:bl buffer last。
以上两个指令 elvis 不适用。
如果您是使用 vim 的 GUI,那就在菜单上就会有 Buffers 这个选项,可以很容易的知道及移动各
buffer 间。
5.3 移除缓冲区
:bd(elete) buffer 在未离开 vim 前是不会移除的,可使用这个指令移除。其实移除它干什么呢?vim
是您在叫用时才会载入的,因此这些 buffers 并不是像 cache 一般要占内存的。

5.4 重新编辑
放弃一修改过的文件,重新编辑。
(1)使用命令 :q!强行退出后再vi flname重新进入。
(2)使用命令 :e!强行重编辑更便捷。这样也是会打开文件,但会放弃目前编辑文件的改变,否则如果文
件已有变动,vim 预设是不让您随便离开的。:e! 后不接什么的话,代表舍弃一切修改,重新载入编辑中
文件。
5.5 其他命令
:files 或 :buffers 或 :ls 会列出目前 buffer 中的所有文件。
在 elvis 中可使用 :b 来叫出 buffers。
:f 或 Ctrl-g 显示目前编辑的文件名、是否经过修改及目前光标所在之位置。
:f 文件名 改变编辑中的文件名。(file)
:r 文件名 在光标所在处插入一个文件的内容。(read)
:35 r 文件名 将文件插入至 35 行之后。
gf 这是 vim 的特殊打开文件的方法,会打开光标所在处的 word 为名的文件,当然,这个文件要在当
前目录内,否则会创建新文件。
6. 查找命令
用/查找单词后,n可以跳到下一个,N则是上一个,:nohls可以取消高亮
查找时,:set ignorecase”项让VIM忽略大小写,“:set noignorecase” 来关闭这项功能。
7. 修改文字
cw:删除一个单词并进入插入模式,cc:删除一行并进入插入模式。
r:然后输入的字母将替换当前字母并保持命令模式,R则是不停的替换(一个挨着一个)。
0到行首,$到行尾。
8. 函数间跳转

ctrl+]和ctrl+T分别是查找函数的定义和返回,好像需要ctag的支持
i 跳转到光标所指标识符的定义行,是打开一个新的小窗口显示,记住要加个i,最好是找自己项目下
的文件,否则找库函数的话还不如man.
大写 K 看光标所指标识符的 man 帮助页

9. 窗口命令

= ctrl+w
:split 文件名 同时在一个页面显示多个文件的内容,类似多窗口,用切换当前窗口
f 切分显示光标在处的文件名,VIM 会在 path 中搜索该文件名,比如常用它打开 #include 语句
中的文件
_ 当同时打开几个文件时,按 _ 使当前窗口最大化
用Ctrl-W命令指定光标移动:
Ctrl-W + 扩大窗口
Ctrl-W - 缩小窗口
Ctrl-W h 移动到窗口左边
Ctrl-W j 移动到窗口下边
Ctrl-W k 移动到窗口上边
Ctrl-W l 移动到窗口右边
等于是按下后,松开键盘,再按下一个命令就可以了.
如果要关闭分割窗口可以用:close,剩下只有一个窗口的话就不能关了。
多窗口是split,像用e打开多个文件是将文件放在缓冲区中。

10. 自动完成
i 向上搜索,补全一个词
i 向下搜索,补全一个词
i 补全一行。
比如你写过一行 for (int i = 0; i <>
即可。如果补全出来的不是你想要的那一行,你可以按 选择上一个或下一个匹配行
i 在文件系统中搜索,补全一个文件名
如果按 补全一个词,在当前文件中没有找到匹配,VIM 将搜索 #include 语句中的文件
,而文件的位置将在 path 中搜索。
i 把上一行对应列的字符抄下来
i 把下一行对应列的字符抄上来,这两个都可以一直按下去,到了行尾自己会停的.

11. 注释整块内容
注释块的方法:
选定要注释掉的行 I // Esc
I之后输入的东西就是插入到选定的行前边的,直至Esc.
要去掉注释的办法:选定注释符//,然后d
列块选定后I是在前边都插入,A是在后边都插入
是按列块模式的选定,是行选定,v是普通选定
12. 其他命令
u可以撤销上一步操作, ctrl+r可以恢复
i命令 执行一个普通模式的命令,执行完毕后回到插入模式,不用多次Esc
i后续字符 输入特殊的 ASCII 字符或键。
. 在光标当前位置处重复上一次操作
:!命令行 执行一条外部命令

vim使用技巧(1),转载

作者:camry.wu@gmail.com

说明:
以下的例子中 xxx 表示在命令模式下输入 xxx 并回车
以下的例子中 :xxx 表示在扩展模式下输入 xxx 并回车
小括号中的命令表示相关命令.
在编辑模式或可视模式下输入的命令会另外注明.

1. 查找

/xxx(?xxx) 表示在整篇文档中搜索匹配xxx的字符串, / 表示向下查找, ? 表示
向上查找.其中xxx可以是正规表达式,关于正规式就不多说了.
一般来说是区分大小写的, 要想不区分大小写, 那得先输入
:set ignorecase
查找到以后, 再输入 n 查找下一个匹配处, 输入 N 反方向查找.

*(#) 当光标停留在某个单词上时, 输入这条命令表示查找与该单词匹配的
下(上)一个单词. 同样, 再输入 n 查找下一个匹配处, 输入 N 反方
向查找.

g*(g#) 此命令与上条命令相似, 只不过它不完全匹配光标所在处的单词, 而
是匹配包含该单词的所有字符串.

gd 本命令查找与光标所在单词相匹配的单词, 并将光标停留在文档的非
注释段中第一次出现这个单词的地方.

% 本命令查找与光标所在处相匹配的反括号, 包括 () [] {}

f(F)x 本命令表示在光标所在行进行查找, 查找光标右(左)方第一个x字符.
找到后:
输入 ; 表示继续往下找
输入 , 表示反方向查找

2. 快速移动光标
在 vi 中, 移动光标和编辑是两件事, 正因为区分开来, 所以可以很方便的进行光标定
位和编辑. 因此能更快一点移动光标是很有用的.

w(e) 移动光标到下一个单词.
b 移动光标到上一个单词.

0 移动光标到本行最开头.
^ 移动光标到本行最开头的字符处.
$ 移动光标到本行结尾处.

H 移动光标到屏幕的首行.
M 移动光标到屏幕的中间一行.
L 移动光标到屏幕的尾行.
gg 移动光标到文档首行.
G 移动光标到文档尾行.
c-f (即 ctrl 键与 f 键一同按下) 本命令即 page down.
c-b (即 ctrl 键与 b 键一同按下, 后同) 本命令即 page up.

'' 此命令相当有用, 它移动光标到上一个标记处, 比如用 gd, * 等查
找到某个单词后, 再输入此命令则回到上次停留的位置.

'. 此命令相当好使, 它移动光标到上一次的修改行.

`. 此命令相当强大, 它移动光标到上一次的修改点.

3. 拷贝, 删除与粘贴
在 vi 中 y 表示拷贝, d 表示删除, p 表示粘贴. 其中拷贝与删除是与光标移动命令
结合的, 看几个例子就能够明白了.

yw 表示拷贝从当前光标到光标所在单词结尾的内容.
dw 表示删除从当前光标到光标所在单词结尾的内容.
y0 表示拷贝从当前光标到光标所在行首的内容.
d0 表示删除从当前光标到光标所在行首的内容.
y$ 表示拷贝从当前光标到光标所在行尾的内容.
d$ 表示删除从当前光标到光标所在行尾的内容.
yfa 表示拷贝从当前光标到光标后面的第一个a字符之间的内容.
dfa 表示删除从当前光标到光标后面的第一个a字符之间的内容.

特殊地:
yy 表示拷贝光标所在行.
dd 表示删除光标所在行.
D 表示删除从当前光标到光标所在行尾的内容.

关于拷贝, 删除和粘贴的复杂用法与寄存器有关, 可以自行查询.

4. 数字与命令
在 vi 中数字与命令结合往往表示重复进行此命令, 若在扩展模式的开头出现则表示行
号定位. 如:

5fx 表示查找光标后第 5 个 x 字符.

5w(e) 移动光标到下五个单词.

5yy 表示拷贝光标以下 5 行.
5dd 表示删除光标以下 5 行.

y2fa 表示拷贝从当前光标到光标后面的第二个a字符之间的内容.

:12,24y 表示拷贝第12行到第24行之间的内容.
:12,y 表示拷贝第12行到光标所在行之间的内容.
:,24y 表示拷贝光标所在行到第24行之间的内容. 删除类似.

5. 快速输入字符
在 vi 中, 不要求你输入每一个字符, 可以有很多种方法快速输入一些字符.
使用 linux/unix 的同学一定有一个经验, 在命令行下输入命令时敲入头几个字符再按
TAB 系统就会自动将剩下的字符补齐, 假如有多个匹配则会打印出来. 这就是著名的命令
补齐(其实windows中也有文件名补齐功能). vi 中有许多的字符串补齐命令, 非常方便.

c-p(c-n) 在编辑模式中, 输入几个字符后再输入此命令则 vi 开始向上(下)搜
索开头与其匹配的单词并补齐, 不断输入此命令则循环查找. 此命令
会在所有在这个 vim 程序中打开的文件中进行匹配.

c-x-l 在编辑模式中, 此命令快速补齐整行内容, 但是仅在本窗口中出现的
文档中进行匹配.

c-x-f 在编辑模式中, 这个命令表示补齐文件名. 如输入:
/usr/local/tom 后再输入此命令则它会自动匹配出:
/usr/local/tomcat/

abbr 即缩写. 这是一个宏操作, 可以在编辑模式中用一个缩写代替另一个
字符串. 比如编写java文件的常常输入 System.out.println, 这很
是麻烦, 所以应该用缩写来减少敲字. 可以这么做:
:abbr sprt System.out.println
以后在输入sprt后再输入其他非字母符号, 它就会自动扩展为System.
out.println

6. 替换
替换是 vi 的强项, 因为可以用正规表达式来匹配字符串.以下提供几个例子.

:s/aa/bb/g 将光标所在行出现的所有包含 aa 的字符串中的 aa 替换为 bb
:s/\/bb/g 将光标所在行出现的所有 aa 替换为 bb, 仅替换 aa 这个单词
:%s/aa/bb/g 将文档中出现的所有包含 aa 的字符串中的 aa 替换为 bb
:12,23s/aa/bb/g 将从12行到23行中出现的所有包含 aa 的字符串中的 aa 替换为 bb
:12,23s/^/#/ 将从12行到23行的行首加入 # 字符
:%s= *$== 将所有行尾多余的空格删除
:g/^\s*$/d 将所有不包含字符(空格也不包含)的空行删除.

7. 多文件编辑
在一个 vim 程序中打开很多文件进行编辑是挺方便的.

:sp(:vsp) 文件名 vim 将分割出一个横(纵)向窗口, 并在该窗口中打开新文件.
从 vim6.0 开始, 文件名可以是一个目录的名称, 这样, vim 会
把该目录打开并显示文件列表, 在文件名上按回车则在本窗口打
开该文件, 若输入 O 则在新窗口中打开该文件, 输入 ? 可以看
到帮助信息.

:e 文件名 vim 将在原窗口中打开新的文件, 若旧文件编辑过, 会要求保存.

c-w-w vim 分割了好几个窗口怎么办? 输入此命令可以将光标循环定位
到各个窗口之中.

:ls 此命令查看本 vim 程序已经打开了多少个文件, 在屏幕的最下方
会显示出如下数据:
1 %a "usevim.html" 行 162
2 # "xxxxxx.html" 行 0

其中:
1 表示打开的文件序号, 这个序号很有用处.
%a 表示文件代号, % 表示当前编辑的文件,
# 表示上次编辑的文件
"usevim.html" 表示文件名.
行 162 表示光标位置.

:b 序号(代号) 此命令将指定序号(代号)的文件在本窗口打开, 其中的序号(代号)
就是用 :ls 命令看到的.

:set diff 此命令用于比较两个文件, 可以用
:vsp filename
命令打开另一个文件, 然后在每个文件窗口中输入此命令,就能看
到效果了.

8. 宏替换
vi 不仅可以用 abbr 来替换文字, 也可以进行命令的宏定义. 有些命令输起来很费劲,
因此我把它们定义到 - 上, 这样就很方便了.这些配置可以预先写到 ~/.vimrc
(windows 下为 $VIM/_vimrc) 中, 写进去的时候不用写前面的冒号.

:nmap :nohls 取消被搜索字串的高亮
:nmap w 命令模式下转移光标到不同窗口
:imap 输入模式下运行
:nmap :%s= *$== 删除所有行尾多余的空格.
:imap 同上

:java 中: (注, 这里为什么说 java 中, 因为以下定义对其他文件格式不起作用, 下文
会说到如何实现这一点)
:nmap :comp javac:mak -d . %
此命令用 javac 编译 java 文件, 它会自动将光标定位到出错点. 不过这需要定
义一个 javac.vim 文件在 $VIM/compiler 下, 在 javac.vim 里面只有两行字:
setlocal makeprg=javac
setlocal errorformat=%A%f:%l:\ %m,%-Z%p^,%-C%.%#

:nmap :comp ant:mak
此命令用 ant 编译 java 文件, 它会自动将光标定位到出错点. 一般来说, 安装
vim 后已经有了compiler/ant.vim文件, 因此这个命令可以直接使用. 但是需要
在当前目录下有 build.xml 文件, 当然还必须安装 ant 才行.

:nmap :cl 此命令用于查看所有的编译错误.
:imap

:nmap :cc 此命令用于查看当前的编译错误.
:imap

:nmap :cn 此命令用于跳到下一个出错位置.
:imap

:nmap :cp 此命令用于跳到上一个出错位置.
:imap

:nmap :JavaBrowser
此命令用于在窗口左部分割出一个新窗口, 里面的内容是 java 的资源树, 包括
本文件中出现的类, 类的成员变量及成员方法, 就好像 JCreator 表现的那样.
在这个窗口中输入 ? 会看到帮助. 嘿嘿, 很好用, 不过需要 ctags 支持.
:imap

9. TAB
TAB 就是制表符, 单独拿出来做一节是因为这个东西确实很有用.

<< 输入此命令则光标所在行向左移动一个 tab.
>> 输入此命令则光标所在行向右移动一个 tab.
5>> 输入此命令则光标后 5 行向右移动一个 tab.
:12,24> 此命令将12行到14行的数据都向右移动一个 tab.
:12,24>> 此命令将12行到14行的数据都向右移动两个 tab.

那么如何定义 tab 的大小呢? 有人愿意使用 8 个空格位, 有人用4个, 有的用2个.
有的人希望 tab 完全用空格代替, 也有的人希望 tab 就是 tab. 没关系, vim 能
帮助你.以下的设置一般也都先写入配置文件中, 免得老敲.

:set shiftwidth=4 设置自动缩进 4 个空格, 当然要设自动缩进先.
:set sts=4 即设置 softtabstop 为 4. 输入 tab 后就跳了 4 格.
:set tabstop=4 实际的 tab 即为 4 个空格, 而不是缺省的 8 个.
:set expandtab 在输入 tab 后, vim 用恰当的空格来填充这个 tab.

10. autocmd
这个命令十分的强大, 可以用这个命令实现对不同的文件格式应用不同的配置; 可以
在新建文件时自动添加上版权声明等等. 这些命令一般定义在 ~/.vimrc 这样的配置文件
里面. 由于他很强大, 所以我不能给出很具体的说明, 只能举几个例子, 详细的请看帮助.

:autocmd! 删除所有之前的自动命令.
autocmd FileType java source ~/.vim/files/java.vim
autocmd FileType java source ~/.vim/files/jcommenter.vim
以上两条命令让我在打开 java 文件时才应用后面提到的两个配置文件.
autocmd BufNewFile *.java 0r ~/.vim/files/skeletons/java.skel
以上这条命令让我在新建 java 文件时自动加入 java.skel 文件的内容.
autocmd BufNewFile *.java normal gnp
以上这条命令让我在新建 java 文件时自动运行 gnp 命令, 这个命令进行一些特殊化
处理, 比如将新 java 文件中的 __date__ 替换成今天的日期什么的.

11. 常用脚本
在 vim.sf.net 你可以发现很多脚本(script), 这些脚本常常有让你意想不到的作用.
我常用的有:

jcommenter.vim 自动加入 javadoc 风格的注释.
JBrowser.vim 类资源浏览. C, C++ 等可以用 Tlist

还有许多有用的, 比如 checkstyle.vim 可以检验你的编程风格, jad.vim 可以直接
反编译 .class 文件等等.

12. 常用配置
在~/.vimrc 配置文件中你常常需要一些个性化配置. 比如上面写的一些宏定义, 一些
autocmd 定义等等. 比如:

set suffixes=.bak,~,.o,.h,.info,.swp,.aux,.bbl,.blg,.dvi,.lof,.log,.lot,.ps,.toc
这样在vim中打开文件时, 按 tab 键补齐文件名时它会忽略上述文件.

set nu 显示行号
set ai 设置自动缩进
map Y y$ 让 Y 和 D 一样, 要不然 Y 的本意和 yy 一样.

13. 其他
还有许多有意思的命令, 记录在这里免得忘记.

. 重复上次编辑命令.
:g/^/exec "s/^/".strpart(line(".")." ", 0, 4) 在行首插入行号
:runtime! syntax/2html.vim 转换 txt 成 html, 会按照你的颜色配置来转

2007年11月3日星期六

blogger什么时候才能不用代理就上啊?

为什么blogger要被封呢?
不理解啊。。。

2007年5月2日星期三

graphicx宏包的includegraphic命令足够处理绝大部分latex中的图片问题

还以为LaTeX里的图片排版是个很麻烦的事情,想找CCT和CJK的图片排版宏又没找到,结果就在ctex.org的LaTeX文档乱翻,就看到graphicx的宏包文档,graphicx就已经ctex.org的CTEX套装里集成好了,中科院博士论文模板用的其实也是graphicx宏,只是他的示例太少了,没充分展示graphicx的威力。。。
我在下边转载文档中的一部分,记录一下:

http://www.ctex.org/documents/latex/graphics/node20.html


7.1 includegraphics 命令


\includegraphics[选项]{文件} 这里的选项在表 7.1, 7.2, 7.3 中列出。 因为 \includegraphics 不会结束 当前段落,所以它能够在文本中放置图形如 \includegraphics[width=12pt]{recycle.eps}\includegraphics[width=12pt]{illusion.eps}。下面的命令将以 file.eps 的自然大小插入到 LATEX 文档中:

\documentclass{article}
\usepackage{graphicx}
\begin{document}
\includegraphics{file.eps}
\end{document}


表 7.1: includegraphics Options
height 图形的高度(可为任何 TEX 度量单位)。
totalheight 图形的全部高度,可为任何 TEX 度量单位( 6/95 增加)。
width 图形的宽度(可为任何 TEX 度量单位)。
scale 图形的缩放因子,设定 scale=2 会使 插入的图形的大小为其自然大小的两倍。
angle 设定旋转的角度,以度为单位,顺时钟方向为正。
origin origin 指定图形绕那一点旋转,缺省 是图形的参考点(12/95 增加)。初始点有可能与 第 8.3节的 \rotatebox 命令中的一样。 比如 origin=c 将使图形绕它的中心旋转。
bb 设定 BoundingBox 的值。 bb=10 20 100 200 设定 BoundingBox 的左下角在 (10,20),右上角在 (100,200)。因为 \includegraphics 会自动从 EPS 文件中读入 BoundingBox 行 所给的值,所以一般不使用 bb 这个选项。但它在 EPS 文件 中的 BoundingBox 丢失或出错时还是很有用的。


表 7.2: includegraphics Cropping Options
viewpoint 指定图形可以被看到的部分。如同 BoundingBox 一样, 这是一个由四个数字,左下角和右上角的坐标所确定的区域。 这里的坐标是相对于 BoundingBox 的左下角的( 6/95 增加)。 例如,如果图形的 BoundingBox 的值是 50 50 410 302viewpoint=50 50 122 122 将显示以图形的左下角为左下角的一英寸大小的区域。 而 viewpoint=338 230 410 302 则会显示以图形的 右上角为右上角的一英寸大小的区域。 必须使用 clip 选项(见表 7.3) 来阻止显示视图以外的图形部分 。
trim 指定图形可以被看到的部分的另一选项。所给出的四个数字 分别代表了从左、下、右、上被截去的值。正数代表从此方向 截去的大小,而负数则代表从此方向加上的大小。


表 7.3: includegraphics Boolean Options
noclip (缺省选项)显示整个的图形,即使有些部分在视图之外。
clip 当使用 clip 时,将不显示图形在视图之外的部分。
draft 当使用 draft 选项时,将只显示图形的 BoundingBox 和文件名,这使得显示和打印文档的速度加快。如果使用 draft 宏包选项,\usepackage[draft]{graphicx} 会导致文档中的所有图形都被以草稿(draft)方式插入。
final (缺省选项,除非使用\usepackage[draft]{graphicx}final 选项使得图形被显示,经常用来覆盖 \usepackage[draft]{graphicx}
keepaspectratio 在没有设定 keepaspectratio 选项时, 给定图形的高度(全部高度)和宽度会导致图形被不对称缩 放来满足所设定的高和宽。在设定 keepaspectratio 选项后,给定图形的高度(全部高度)和宽度时,图形会 保持原有的宽高比例,尽可能使得图形满足所设定的高和宽, 但是图形不会超出其中任一个。

如果加入的图形文件没有指明扩展名,那么 \includegraphics 会根据 \DeclareGraphicsExtensions 的扩展名列表自动为它加上扩展名(见第 9.1 节)。由于缺省的扩展名列表不包括空的扩展名, \includegraphics{file} 不会读入 file。除非空的扩展名 已被加到扩展名列表中。 命令

\includegraphics[width=3in]{file.eps}
file.eps 插入文档并且它的宽度被缩放到 3 英寸,高度也会 按相应的比例缩放。如果用 \textwidth\em 等的函数来 指定宽度,而不是用像 3 英寸这样的固定尺寸,将会使你的 LATEX 文 档更具通用性。例如:

\includegraphics[width=\textwidth]{graphics.eps}
将所插入图形缩放到和文本行的宽度一样宽。而下面的命令

\includegraphics[width=0.80\textwidth]{graphics.eps}
使得插入图形的宽度为文本行宽的 80%。当与 calc 宏包配合使用 时,下面的命令可令图形的宽度比文本行宽少 2 英寸:

\includegraphics[width=\textwidth-2.0in]{graphics.eps}
to (需要 graphicx 12/95 或以后的 版本。) 下面是一些使用 \includegraphics 命令来插入图形的 例子。这里为方便起见,定义 \HR 如下:

\newcommand{\HR}{\rule{1em}{0.4pt}}
在下面的几个例子中,可以比较以下使用 scale,width,height,angle 以及 keepaspectratio 选项及其不同的顺序所得到的不同效果。


Wang Lei
2000-04-15

使用批处理命令结合convert把gif图像转成eps图像

用中科院的LaTeX博士论文模板帮mia的论文排版,碰到一个比较头疼的问题,怎么把一大堆gif图像转称eps。。。
看了《大家一起学latex》之后,发现imagemagic的免费图像处理软件,里边有各convert.exe命令行工具,可以把n多种图片格式转化成n多种图片格式。

之前我用photoshop(or photoshit)手工一个一个转成了eps,然后用includegraphic引用到tex文档里,编译的时候居然提示说,没有加尺寸边框,一些控制eps大小的参数无法起作用。。。
md,还好意思卖这么贵,幸亏用的是评估版。。。

于是下载了imagemagic,安装。。。
安装目录下就有这个可爱的convert.exe。。。
可是手工一个一个敲命令也讨厌。。。
预示查了一下批处理命令的使用方法。。。写了一个批处理命令:
@echo off
for %%f in (*.gif) do .\convert.exe %%f %%f.eps
pause
双击运行,解决问题,整个世界都如此清爽。。。。

2007年4月25日星期三

如何让我的M-Audio MobilePre在Ubuntu下正常使用

安装Ubuntu6.10的时候,Device Manager似乎都识别出了我的两个声卡。。
一个是我的KT600主板上自带的Realtec AC97兼容声卡,好像Chip是ALCxxxx。。
另一个就是我作音乐用的,支持ASIO的M-Audio MobilePre USB声卡。。。。

可是Ubuntu用了一种Alsa驱动,只能驱动我的Realtec AC97,而我根本就不想用这个声卡。。。
我的MobilePre在M-Audio的官方网站上有各种MS Windows和Mac操作系统下的驱动。。。
简直是其实我们GNU/Linux用户嘛。。。

怎么办,Google it!,,,
keyword: linux driver MobilePre M-audio。。。
就会发现www.opensound.com,实际上在M-Audio的官方也可以搜得到相关的FAQ上人家介绍说:
有个叫4Front的组织,提供免费的多种Prefessional Audio Interface在Unix和Unix like下的驱动,
个人免费使用,支持和商业使用需要money。。。很公平,不是么。。。

于是,去opensound下载名为:oss-linux_v4.0-1002.deb的deb包,然后根据它的install instruction:
ctr+alt+<F1>进入console;
以root身份登录;
运行dpkg -I oss-linux_v4.0-1002.deb;
然后重新启动。。。

然后,居然听到login theme music,瓦哈哈哈哈!
赶紧打开VLC,打开mp3,mav,avi,全都有声音,质量也不错,哈哈哈,不错!!

到device manager里看看:



多了两个OSS Sequencer Device,当然一个是为AC97,一个MobilePre。。
再看MobilePre下多了:
一个USB Audio OSS Control Device
两个USB Audio OSS PCM Device。。。。

2007年4月22日星期日

使用CSS+dvi之后何时使用table

转自:http://www.chinaz.com/Design/Rules/03225T92007.html
使用WEB标准之后,并不是说排除表格的使用,表格并不是鸡肋,而正好相反是一道大餐, 之所以在很多关于CSS布局的文章中常提到"为什么使用表格排版是不明智的"这句话,可能是大家对他的理解有误,这里注意一点"使用表格排版"是"不明智 "的.指的是我们使用了很多年的,用表格来排版是不明智的,表格归根截底是一种显示"数据"的方式,大家可以想象一下EXCEL,表格就是起这个使用的, 有的时候信息使用表格显示让我们能清晰易读,所以才使用表格,比如公司员工联系表,产品与型号对应表等.

那么所谓表格大餐呢,其实意见上升到了一个层次,也就是说你如果能像专业市场分析公司那样,灵活使用表格来显示客户数据和调查数据等消息的时候,那才是真正利用了表格的优势.

所以,关于那句使用以久的话,应该改为"使用表格作为网页排版, 布局页面元素是不合理的,表格是用来显示数据的"。

关于其它元素

我这里按我的使用经验,把XHTML标准中的一些元素,分为三大类:

第一类是我称之为辅助布局设计元素:

这里我指的是DIV,SPAN等,这类元素的主要功能是用来布局整个页面的,灵活使用这些元素的各种属性,可以让你的页面表现丰富多彩.

第二类我称为结构化元素或叫信息元素

这里指的是TABLE,UL,PRE,CODE类元素是一种信息显示与整理方式,比如TABLE很明显就是用来显示表格信息的,UL是用来显示列化信息的,当需要用表格或列表的时候,用这二种方式来显示是明智的。

第三类指的是 这样的,完全是为了实现一些功能,如填上关键字的META keyword,还有做链接的A

那么正确的符合标准的设计思路是:

使用DIV等布局元素来制作页面的设计布局,定位,色块,图片等

使用TABLE,UL等这样的元素来显示页面中需要展示数据

当然,DIV也起整理数据的作用,使用DIV的ID属性可以很方便的将一个DIV作为一个你名命的数据块。

所以使用WEB标准来制作网站,实际是一个信息合理化整合的一个过程,什么地方该用什么元素还是照用不误,别把表格当布局工具就行。

2007年4月16日星期一

合成器系列----粒子合成器
转载自:http://ch.midifan.com/m_TechArticle/Detail.aspx?id=542
【上】坚果壳中的声音



离子合成(Granular Synthesis)的声音合成方法越来越多的出现在现今的软件合成器中,何谓离子?离子合成又是怎样的?本文来做简单解释。

现 成的一个声音,将被切碎成成千上万的部分,每个部分就叫做一个微粒(grain),离子合成也就因此而得名,再使用这些微粒进行重新排列组合和处理,就得 到了新的声音,这便是离子合成的大致过程。这种使用无数微粒合成声音的方法可以追溯到1947年,一个叫做Denis Gabor的物理学家在《Nature》(自然)杂志发表了一篇名为《Acoustic Quanta and the Theory of Hearing》(声学量子与听觉理论)的论文,在那之后离子合成有了众多的追随者,其中著名的有Iannis Xenakis,Curtis Roads(最先将离子合成与电脑结合起来的人),Barry Truax。

那为什么离子合成在近两年才流行起来呢?按照离子合成的原 理,你不仅可以改变那些成千上万的微粒的音色、长度、音高、频率,还可以将他们按不同顺序再重新排列组合起来。由于可调参数众多,而离子数量更是多的离 谱,在电脑技术和速度都很低的50年代,实现起来有很大的难度。所以离子合成直到90年代才“死灰复燃”了,可见理论永远走在成品的前面。

离子合成,就像坚果壳中的声音!

坚果壳由两个部分组成,果壳和壳中的果肉。在离子合成中,果壳就是声音包络,而果肉就是组成声音的波形。单独的声音微粒也许看不出什么,但成千上万的微粒组成一个完整声音的时候,“果壳”和“果肉”将决定这个声音的最终形态。

首先来看“果肉”——微粒的波形

微 粒的“果肉”可以由任何波形构成,最简单的波形就是正弦波了,其也是最纯净的波形,不含有任何谐波,但在离子合成中,最纯净的正弦波并不适于创造出非常棒 的声音,但因为其波形简单,便于理解,所以我们还是使用正弦波为例子。下图为正弦波的波形。(加法合成就是使用正弦波的,而离子合成的基础就是加法合成)



你 可以定义正弦波的频率(也就是每秒种震荡的次数),但因为正弦波是无限延伸的,所以在一般的合成器上无法定义其震荡的时间长度,而离子合成就可以做到这一 点,不过被限定时间长度的正弦波在这里就不叫正弦波了,而被称为正弦微粒。下图为一个正弦微粒,其时间被限定为0.020秒,而两端的振幅都被衰减了,看 起来像一个坚果壳。



不仅是简单的正弦波形,采样音色也可以作为微粒使用。采样音色的长度将被拉伸或压缩到你需要的微粒长度,而且是只改变采样音色的长度而音高保持不变。

在离子合成中有两类采样音色:长采样和短采样,他们在离子合成中的使用方法是不同的。短采样的长度可以直接当做一个微粒来使用,而长采样可以被切割成多达一系列的微粒使用,当然你可以只使用其中某几个微粒。

下图为一个采样音色:



下图为此采样音色被作为微粒使用,两端的振幅都被衰减了,大体看起来像一个坚果壳。



再来了解“果壳”——微粒的包络

“果壳”决定了微粒的长度和振幅。为微粒加包络的处理方法叫做“开窗术”(windowing,是一种振幅调制的技术),其方法如下图所示。我们不是声音工程师没必要了解如何加包络,所以下图的内容也不必理会,我们需要了解的是:微粒的包络是怎样的。



微 粒的包络不是我们熟悉的ADSR(Attack-Decay-Sustain-Release),而包含了更为丰富的内容:Attack(上冲)、 Sustain(保持)、Decay(衰减)、Amplitude(振幅)、Duration(持续时间)。下图为一个微粒的包络,如果你对声音合成比较 了解的话,不用我讲看图就都明白了。



Duration(持续时间):其决定了一个微粒的持续时间,一般来说10-50毫秒是最佳时间长度。如果微粒的持续时间较短,其会占用更多的频谱带宽而带来噪音,使得声音浑浊不清。

Amplitude(振幅):振幅决定着微粒的音量,最大只能到100%,也就是说微粒的声音不能变大,只能按比例减小。

Attack(上冲):上冲时间决定着微粒从最开始到最大音量持续的时间长短,很短的上冲时间会带来噪音,还有一些边带频谱,这都是我们不希望得到的。

Sustain (保持):保持时间决定着在上冲之后,微粒在最大振幅停留的时间。如果微粒的duration时间很长而sustain时间很短,就会产生一些噪音。一般 来说在离子合成中不能调整Sustain的时间,其长短是由duration-attack-decay得出的。

Decay(衰减):衰减时间决定了微粒由最大振幅到无声的时间,在离子合成中decay的时间与attack时间可以不相同(也就是说果壳的两头不一定是一样尖的),但是不同的attack和decay会带来噪音和频谱的边带,所以一般情况下果壳的两头还是一样尖的。

看到这里,也许你会认为,啊原来微粒的包络都是这个样子的:



哈,那你就小瞧了离子合成中的微粒的,实际上他还可以是这个样子的:



甚至还可以是这个样子:



看完上面3个图你明白了吧,微粒包络中的振幅,可以是直线,也可以是带有拐点的直线,甚至可以是曲线!

本文根据《Sound in a nutshell—Granular Synthesis》以及《real-time granular synthesis》部分内容编译

【下】微粒的截取与组合
转载自:http://ch.midifan.com/m_TechArticle/Detail.aspx?id=543



在上一讲我们已经了解了离子合成的概念,以及微粒的两个特性:果壳和果肉。那么这些成千上万的微粒是如何组合在一起形成最后的声音的呢?方法有二:同步和异步。

首先看同步的离子合成:

使用同步的离子合成方法,所有的微粒的时间长度都是相同的,或者是一种线性递增/递减的关系。

同步的离子合成可以分别调节每个微粒的Amplitude(振幅)、Grain Density(微粒密度)、Pitch(音高)、Inter-onset time(开始时间)。

Grain Density(微粒密度)是离子合成器中比较重要的一个参数,其决定了微粒的分布,以每秒内的微粒数量为单位。每秒低于30个微粒就算是低密度了,这样 做可以使最后发出的声音带有一些节奏感。就像我说哎——呦——啊(长音连读),在低密度情况下,就成了哎(停)哎(停)呦(停)呦(停)啊(停)啊 (停),中间加入了小段的停顿,带来一些节奏的感觉。随着密度的增大,声音频谱就会越复杂,声音的振幅(也就是音量)也会越大,音高会变高。

密度与微粒持续时间之间的关系也会带来声音的变化,单个微粒的持续时间越短,微粒密度越大,那么声音产生的重叠就越多。

Inter-onset time(开始时间)决定了两个临近微粒间的持续时间,这个参数不能自己定义,而是使用密度计算出来的。

再来看异步的离子合成:

使 用异步的离子合成方法,所有微粒都是随机截取的,他们之间的时间关系不像同步离子合成那样是线性的,而是完全没有规律的。但其可调参数与同步离子合成是相 同的,包含了Amplitude(振幅)、Grain Density(微粒密度)、Pitch(音高)、Inter-onset time(开始时间)。

Grain Density(微粒密度)参数同样是以每秒内的微粒数量为单位。在同步离子合成中200微粒/秒表示在一秒的时间内平均截取200个微粒,密度越大音高越高。而在异步离子合成中,这200个微粒是随机截取的,密度与音高没有任何关系。

不管是同步还是异步,所有微粒最后都是按照截取的顺序来排列的,这样才能形成与原采样类似的声音。当然如果是直接使用离子合成新的声音而不是改造采样音色,那么微粒的顺序也可以随机排列。

修整所有微粒组成的声音:

打个比方,每个微粒就好比大树的每片叶子,叶子的形状、颜色都决定了整棵树的外观,不同的叶子代表了不同的树。而微粒组成的整个音色就好比由所有叶子组成的整棵大树,园丁在修剪树木时不是修剪每片叶子(如果是这样,园丁早就累死了),而是对睁棵树的形状、长势做修整。

在离子合成中,我们可以对单个微粒做细致的修改,当然也可以对所有微粒组成的整个声音做修改。我们可以使用几乎所有合成方法来为所有微粒组成的整个声音做修改,在不同的离子合成器中使用的方法也都不同,这里就不列举了。

好 了,到此为止你应该大致了解了离子合成的概念了。简单的说就是将一个采样音色分为成千上万个的微粒,每个微粒的包络都是可调的,而截取微粒的时间长度,密 度也是可调的,截取之后再按照原来的顺序拼接在一起,形成新的声音。当然你也可以使用各种波形比如正弦波、锯齿波、脉冲波组成成千上万个微粒,通过改变包 络,和一些上面讲到的参数,组成全新的充满个性的声音,这就比较难了,而且合成出的声音可能会比较“没谱”,不要气馁,慢慢探索,声音合成光有理论是不够 的,就是要多试多鼓捣,时间长了你就是声音合成的大师了,哈,大师们慢走,以后见。

本文根据《Sound in a nutshell—Granular Synthesis》以及《real-time granular synthesis》部分内容编译




安装Gaim,beta2.03之后就内置qq插件了

1。#安装SVN工具
代码:
sudo apt-get install subversion

2。#安装编译工具和依赖包
代码:
sudo apt-get install build-essential libglib2.0-dev libgtk2.0-dev libgnutls-dev intltool libtool libgstreamer0.10-dev libgtkspell-dev

3。#让gaim支持声效
代码:
sudo apt-get install libao-dev libaudiofile-dev gstreamer0.10-plugins-good

4。#取回源代码
代码:
svn co https://svn.sourceforge.net/svnroot/gaim/trunk gaim

5。
代码:
cd gaim
./autogen.sh
./configure --enable-gnutls=yes
make
sudo make install

2007年4月15日星期日

在linux上安装JDK,very helpful...

转自:http://forum.ubuntu.org.cn/about34307.html

Sun JDK/JRE在Windows上安装很方便,但是在Linux上安装给很多人造成了不少麻烦,这几天我查了不少文章,终于总结出一套较为完整的方案。我是在Ubuntu 6.10上试验的,当然也适合于其他版本的Linux。

Sun发布的JDK/JRE有两种版本,一种是.rpm.bin格式的,另一种则是.bin格式的,前者我没有试,但是我想应该是适合于rpm的,可能会 安装到/usr里面去,而且自动化程度可以高一些。后者则完全是绿色软件,只是做一个解压的动作。下面我就来讲后者的安装全攻略。

1、首先我们要到Sun的网站上去下载JDK/JRE(点这里进入),最新的正式版本已经是6.0(也就是1.6),当然老的版本Sun也仍然提供下载,点上面的“Previous Releases”就可以找到了。下载.bin文件,下面假设这个文件的名字是jdk1.x.bin。

2、把安装文件解压出来。假设我们下载的文件保存在/opt下。

打开终端,运行以下命令:
引用:
cd /opt
chmod a+x jdk1.x.bin
./jdk1.x.bin


你会看到版权提示,不管它,按空格键翻页。然后会提示你是否同意版权协议[yes/no],此时输入yes,回车,安装程序就会把文件解压到当前目录下的jdk1.x这样的目录下面(JRE应该大体相同)。

3、让JDK/JRE支持中文。由于默认安装的JDK/JRE不带中文字体,不支持中文显示,所以我们要自行修改某些字体相关的配置,让它们支持中文。

设定字体有两种方法:

第一种方法是把你的中文字体目录做个连接到jdk/jre/lib/fonts里面,这种方法很简便。看命令:
引用:
cd /opt/jdk1.x/jre/lib/fonts
ln -s /usr/share/fonts/truetype/windows fallback (假设我们的中文字体放在/usr/share/fonts/truetype/windows目录里,这个目录里我放的是从Windows那边copy过来的字体)

为什么要做fallback这个连接,我也是从网上看到的,我想应该是Sun做的设定吧,设定JDK/JRE在运行时会到这个目录里去找那些非西 方字体。这种方法对JDK/JRE 1.4/1.5/1.6都适用,但是由于没有在fontconfig.properties文件里面详细设定字体,所以这种方法显示出来的字体很难看。

第二种方法是把配置好的fontconfig.properties做个连接到jdk1.x/jre/lib里面。看命令:
引用:
cd /opt/jdk1.x/jre/lib
ln -s /etc/java/fontconfig.properties (假设我们的fontconfig.properties放在/etc/java目录里)

这种方法对JDK/JRE 1.4/1.5/1.6都适用,只不过1.4版本的文件名是font.properties而不是fontconfig.properties。当然你也 可以直接把fontconfig.properties文件复制到/opt/jdk1.x/jre/lib里面,这样就不用做连接,但是如果你同时安装几 个不同版本的JDK,还是做连接比较方便。在下面我会把我配置好的font.properties和fontconfig.properties的内容贴 出来,大家稍作修改就可以用了。

3、让Web浏览器支持Java插件(也就是支持Java Applets)。

做一个连接就可以了。看命令:
引用:
cd /usr/lib/firefox/plugins (Ubuntu的firefox插件目录在这里,其它版本以此参考)
ln -s /opt/jdk1.x/jre/plugin/i386/ns7/libjavaplugin_oji.so

然后运行firefox,在地址栏里打入about:plugins,回车,可以看到firefox的插件列表里已经有了Java插件。

如果你用的是其它的浏览器,方法大体也差不多,就是进入浏览器的plugins目录,做一个连接。不过要注意的是,如果你用的浏览器是 mozilla 1.4/netscape 7.0以上的版本,用上面的命令没问题,但是如果你用的浏览器是mozilla 1.2/netscape 7.0以下的版本,Sun有提供另一个插件。这样的话,命令就要改一下了:
引用:
cd /usr/lib/mozilla/plugins
ln -s /opt/jdk1.x/jre/plugin/i386/ns7-gcc29/libjavaplugin_oji.so


4、让Web浏览器支持Java Web Start程序。(可选安装)

如果你不知道Java Web Start程序是什么,看这里:
http://www.stcore.com/java/2006/06/18/1150640682d28890.html

所谓安装,其实就是添加一个mimetype(类似于文件关联),让浏览器知道,遇到Java Web Start程序该用什么程序来处理。

对应mozilla/netscape浏览器的方法:
点击菜单:Edit->Preferences->Navigator->Helper Applications
然后新建一个mimetype:
mimetype是:application/x-java-jnlp-file
extention是:jnlp
关联程序是:/opt/jdk1.x/jre/bin/javaws

对应firefox浏览器的方法:
由于firefox没有直接添加mimetype的方法,所以要改的话需要安装一个Mime Type Editor扩展,看这里:
http://forums.mozine.org/index.php?showtopic=5521

5、为firefox浏览器加入Java Console菜单项。(可选安装)

mozilla/netscape装好java插件之后就有Java Console菜单项,可以方便地调用Java控制台,这对程序员调试程序有用。但是firefox还没有这个菜单项,添加的方法就是解压一个zip文件 到firefox/extension目录。现在我们就来添加,看命令:

引用:
cd /usr/lib/firefox/extensions
unzip /opt/jdk1.x/jre/lib/deploy/ffjcext.zip


重启firefox,就可以看到工具菜单里多了一个Java Console菜单项。

JDK/JRE 1.5及以下版本并没有提供这个firefox扩展,如果要安装的话到这里安装:

https://addons.mozilla.org/firefox/141/

6、把Java工具加入系统菜单。(可选安装)

Ubuntu自带的JDK/JRE会在系统菜单中添加两个Java工具,就是Java Plugin Control Panel和Java Policy Tool。下面我们也为自己安装的JDK/JRE添加两个菜单项。

在Ubuntu的主菜单上点击右键->编辑菜单->首选项->新建项目:

第一项:
图标是:/opt/jdk1.x/jre/plugin/desktop/sun_java.png
名称是:Java Plugin Control Panel (这个随便写)
命令是:/opt/jdk1.x/jre/bin/ControlPanel

第二项:
图标是:/opt/jdk1.x/jre/plugin/desktop/sun_java.png
名称是:Java Policy Tool (这个随便写)
命令是:/opt/jdk1.x/jre/bin/policytool

7、添加JAVA_HOME/JRE_HOME环境变量。(Java开发人员必备)

这里以最常用的bash命令解释器为例,编辑用户目录下的.bashrc或.profile文件。如果你想在所有用户的shell下都生效,就编辑/etc/profile文件。同样都是加入以下内容:

引用:
export JAVA_HOME=/opt/jdk1.x
export JRE_HOME=/opt/jdk1.x/jre
export CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH


至此,Sun JDK/JRE在Linux上的安装过程结束。

XML 和 Java 技术: 数据绑定的多种用法

转载自:http://www.ibm.com/developerworks/cn/xml/x-xjavaforum2.html?S_TACT=105AGX52&S_CMP=techcsdn

XML 和 Java 技术: 数据绑定的多种用法

绑定哪些数据,如何使用它们?


级别: 中级

Brett McLaughlin (brett@newInstance.com), 作家兼编辑, O'Reilly Media Inc.

2007 年 4 月 13 日

除 将 XML 用作一种简单数据格式之外,数据绑定是 XML 最流行的用法之一。即使刚刚入门的程序员也能在一种原生编程语言中使用 XML,并且在大多数情况下完全不需要任何的 XML 专门知识。本文并不是介绍解决方案,取而代之,Brett 介绍了一些讨论主题,鼓励您思考如何使用 XML 和数据绑定。欢迎在 XML 和 Java 技术讨论论坛上与别人一起分享您的想法。

XML 用于业务而非技术

随着 XML 的日趋盛行,人们也越来越注重可用性。 换句话说,程序员和管理者并不希望把 XML 看作是一项技术,拥有自己的语义和词汇结构,而认为它更像是纯粹的数据,访问时不用担心 XML 数据格式的细节。

完成 XML 从技术到业务格式的转换,最简单是方法就是数据绑定,这种说法还有待论证。数据绑定就是使用应用程序编程接口(Application Programming Interface,API)操作 XML 文档中的数据,这样程序员就不必过多地了解 XML,不必使用角括号,或者考虑 CDATA 部分或实体引用等等之类的事情。但即使是使用数据绑定,您也会发现在继续操作之前有大量的选项和重要问题需要仔细考虑。

出于本文讨论的目的,我将介绍两个与数据绑定相关的基本问题:

  1. 通过数据绑定 API 表示数据的方法。
  2. 当数据被视为业务数据时的用法。






表示 XML 数据

在最普通的情况下,数据绑定就是将 XML 文档中的数据转换成正在使用的编程语言中的对象。

用于数据绑定的基于对象的 API

比方说,查看下面这段 XML 代码:

<person>
<firstName>Brett</firstName>
<lastName>McLaughlin</lastName>
<email>brett@newInstance.com</email>
</person>

我们可以将这段代码转换成对象,比方说在 Java™ 代码中,这是一个 Person 类的实例,拥有成员变量 firstNamelastNameemail。实例应该包含代码段中的数据,并且能通过方法调用访问该数据,例如 myPerson.getFirstName() 方法。

用于数据绑定的基于文档的 API

尽管这是最常见的数据绑定方法,但是使用 XML 文档并把整个文档表示成一个对象的 API 也是数据绑定的一种形式。这些 API 包括文档对象模型(Document Object Model,DOM)、JDOM 和 dom4j,所有这些 API 都用于在 Java 编码中创建 XML 文档的对象模型。

在这些模型中,我们使用 rootElement.getChild("firstName").getValue() 之类的调用(或者与之相似的调用,取决于 API 的细节)。虽然这确实需要一些 XML 的基础知识(理解元素是什么以及文档的基本结构),但还是对程序员抽象了解析的细节。这就是数据绑定的本质:能够更多地注意到数据而不是数据显示的格式。

程序员更轻松(有点)

一旦采用了更普通的数据绑定解决方案,如 Sun's JAXB,那么需要注意的底层 XML 语法将会更少。可以真正完全地使用 Java(或者您偏好的编程语言)对象、方法和变量。即使是元素的细节和文档结构也隐藏在了数据绑定处理创建的对象之下。

但是,此处的关键是(经常没有考虑到的)仍然需要将 XML 数据结构与系统中的对象匹配,或者需要在系统中创建匹配所使用的 XML 数据格式的对象。这两种情况到 XML 的映射都不太明显,但它仍然是处理的一部分。

那么是哪一种情况呢?

我在这里概述了两种基本的方法,但是这两种方法并不是像第一眼看上去那样区别很大。使用 DOM 或者 JDOM 之类的 API 时,不管是加载 XML 还是访问数据都需要不断地处理文档的结构。在第二种方法中,使用 JAXB 之类的 API 时,需要预先处理 XML,建立使用 XML 的对象模型(或者有时使用工具为您创建需要的类和对象)。然后,在运行时,将数据更多地作为业务数据来使用,可以不用考虑 XML 了。

如果 XML 不是非常易读的格式,或者并非如希望那样以业务目的分开,或者其格式会经常变化,则第一种方法将会是很好的选择。该方法需要更多一点的 XML 知识以及使用 API(更多地以技术为中心而不是以业务为中心)的能力。

另一方面,如果 XML 是按照业务需求组织的,并且 XML 结构很少变化,则可以一次性的创建类和对象,然后在运行时将数据作为业务数据使用,完全不用担心数据底层的 XML。







如何使用数据?

开发人员常常会疏于考虑:如何根据选择的数据绑定解决方案使用 XML 文档中的数据。但是,这可能是正确决定数据绑定方法的一个最重要的因素。

将对象用于持久数据

将 XML 数据转换成对象实例的数据绑定方法只适用于那些要多次使用的数据。获取 XML 文档中的数据并将其转换为多个对象中的成员变量数据涉及大量的处理工作。要从这个方法中获利,需要多次使用到该数据。

仔细查看一条数据的访问次数,同时也考虑一下使用了多少数据。比如说,假设 XML 中为每个人存储了 20 条数据,但应用程序中只访问了其中的一条,使用大量的资源转换数据却只是为了访问其中的一条。不论怎样计算这都不可能获利。

使用对象在其它组件中隐藏 XML

隐藏存储介质是使用基于对象的方法的另一个重要原因。因此应用程序中可能有一个组件对 Person 对象执行一些特殊的处理。可以从数据库或者 XML 文档或者属性文件中读取 people 数据,然后把这些数据转换成 Person 对象,再把这些对象传递给处理组件。

即使只是暂时使用数据,这也是用对象表示数据的一种很合理的情形。在本例中,如果将数据表示为对象格式,并且应用程序的其它部分已了解如何使用该格 式,则可以获益。同时还避免了组件的数据转化和数据加载,而您只希望使用某种类型的对象来实现相应操作,这很好地实现了应用程序中的关系隔离,而它正是应 该遵循的一条重要的设计原则(应用程序中的每个组件只实现一个功能,并实现好该功能)。

短期,只使用一次的数据

如果没有要重用的数据,而且不以对象的形式将数据传递给应用程序中的另一个组件,则可以考虑使用 DOM 或者 JDOM 之类的 API。这比将 XML 转换成非文档格式所使用的资源少,从而可以全面受益。此方法比以高昂的代价将数据转化为特定于业务的对象、以后却只使用该数据一二次要好得多。

尽管本文的主题是数据绑定,但有一点值得提到的是在这些情况下甚至可以考虑使用 SAX(Simple API for XML)这样的 API,它完全不提供对象模型(以文档或对象格式)。使用它处理 XML 只使用很少的内存和时间,如果确实只需要使用一条数据一到两次,则此方法可让您获益巨大。使用像 SAX 这样的 API 需要更多的了解 XML 的知识,但了解这些知识是非常值得的。

2007年4月13日星期五

Apache FOP Project, mark一下

Apache FOP这个Apache Project好像比较有意思,mark一下


FOP是格式对象处理器的意思,它是一个打印格式化器,它由XSL格式化对象(XSL-FO)驱动。
同时它是一个java应用程序,读入格式化对象(FO)树,并且渲染结果页面成特定的输出格式。目前支持的输出格式包括PDF,PCL,PS,SVG,XML等等。
这种想法和我想移植google doc的实现办法有些相似:
  • ajax结合XML,处理XML文档
  • XML通过XSL保存为ps后台文档,ps后台文档可以处理成PDF输出
  • XML文档同时也可以通过前台XSL显示为“可见”的HTML格式化文档,这个HTML文档和PDF文档应该显示一致。
  • 因而这两个XSL的设计就比较重要。

以下转载自:
http://xmlgraphics.apache.org/fop/

Apache FOP

Introduction

Apache FOP (Formatting Objects Processor) is the world's first print formatter driven by XSL formatting objects (XSL-FO) and the world's first output independent formatter. It is a Java application that reads a formatting object (FO) tree and renders the resulting pages to a specified output. Output formats currently supported include PDF, PCL, PS, SVG, XML (area tree representation), Print, AWT, MIF and TXT. The primary output target is PDF.

Render Diagram

The previous version of FOP (0.20.5) is a partial implementation of the XSL-FO Version 1.0 W3C Recommendation.

The latest stable version of FOP (0.93) is the first stable release after a large redesign effort and implements a larger subset than 0.20.5 of the XSL-FO Version 1.0 W3C Recommendation as well as some parts of the XSL-FO Version 1.1 Working Draft.

Support for each of the standard's objects and properties is detailed in FOP Compliance. Download options include a precompiled version, source code, and many example files to get you started. Resources include links to XSL-FO introductions and many other useful references. A checklist for Getting Help will guide you toward maximizing the usefulness of FOP.

FOP is proud to be part of Apache's XML Graphics project.

Demonstration

Formatting Diagram

This image is a demonstration of a real two page document. The xml data on the left is formatted into the two pages on the right. The document contains static areas that appear on every page, an external graphic, a footnote on the first page, and a table that goes across both pages.

FOP uses the standard XSL-FO file format as input, lays the content out into pages, then renders it to the requested output. One great advantage to using XSL-FO as input is that XSL-FO is itself an XML file, which means that it can be conveniently created from a variety of sources. The most common method is to convert semantic XML to XSL-FO, using an XSLT transformation.

FOP Objectives

The goals of the Apache FOP project are to deliver an XSL-FO to PDF formatter that is compliant to at least the Basic conformance level described in the W3C Recommendation from 15 October 2001, and that complies with the 11 March 1999 Portable Document Format Specification (Version 1.3) from Adobe Systems.

Conformance to the XML 1.0 Recommendation, XSLT 1.0 Recommendation and the XML Namespaces Recommendation is understood. Other relevant documents, such as the XPath and XLink Working Drafts, are referenced as necessary. The FOP Project will attempt to use the latest version of evolving specifications.

The FOP layout system is currently being rewritten to better support the XSL-FO standard.

可爱的 Python: Decorator 简化元编程

转载自:http://www.ibm.com/developerworks/cn/linux/l-cpdecor.html



可爱的 Python: Decorator 简化元编程

用于元编程的最新 Python 工具简介





级别: 高级

David Mertz, Ph. D. (mertz@gnosis.cx), 开发人员, Gnosis Software, Inc.

2007 年 1 月 23 日

Python 使元编程成为可能,不过每个版本的 Python 都有一些细微的区别(并且不是完全兼容),这使我们实现元编程的道路变得更加崎岖。一类函数对象的使用由来已久,同样还有一些技术用于探索和实现魔术般的 属性。在版本 2.2 中,Python 增加了一种很有帮助的定制元类机制,但是其代价就是令用户绞尽脑汁。最近,在 2.4 版本中,Python 增加了 “decorator” ,这是适于执行大部分元编程的最新方式 —— 也是到目前为止对用户最友好的方式。

少劳多得

Decorator 与 Python 之前引入的元编程抽象有着某些共同之处:即使没有这些技术,您也一样可以实现它们所提供的功能。正如 Michele Simionato 和我在 可爱的 Python 专栏的早期文章 中指出的那样,即使在 Python 1.5 中,也可以实现 Python 类的创建,而不需要使用 “元类” 挂钩。

Decorator 根本上的平庸与之非常类似。Decorator 所实现的功能就是修改紧接 Decorator 之后定义的函数和方法。这总是可能的,但这种功能主要是由 Python 2.2 中引入的 classmethod()staticmethod() 内置函数驱动的。在旧式风格中,您可以调用 classmethod(),如下所示:



清单 1. 典型的 “旧式” classmethod
       
class C:
def foo(cls, y):
print "classmethod", cls, y
foo = classmethod(foo)

虽然 classmethod() 是内置函数,但并无独特之处;您也可以使用自己的方法转换函数。例如:



清单 2. 典型的 “旧式” 方法的转换
       
def enhanced(meth):
def new(self, y):
print "I am enhanced"
return meth(self, y)
return new
class C:
def bar(self, x):
print "some method says:", x
bar = enhanced(bar)

decorator 所做的一切就是使您避免重复使用方法名,并且将 decorator 放在方法定义中第一处提及其名称的地方。例如:



清单 3. 典型的 “旧式” classmethod
       
class C:
@classmethod
def foo(cls, y):
print "classmethod", cls, y
@enhanced
def bar(self, x):
print "some method says:", x

decorator 也可以用于正则函数,采用的是与类中的方法相同的方式。令人惊奇的是,这一切是如此简单(严格来说,甚至有些不必要),只需要对语法进行简单修改,所有东 西就可以工作得更好,并且使得程序的论证更加轻松。通过在方法定义的函数之前列出多个 decorator,即可将 decorator 链接在一起;良好的判断可以有助于防止将过多 decorator 链接在一起,不过有时候将几个 decorator 链接在一起是有意义的:



清单 4. 链接 decorator
       
@synchronized
@logging
def myfunc(arg1, arg2, ...):
# ...do something
# decorators are equivalent to ending with:
# myfunc = synchronized(logging(myfunc))
# Nested in that declaration order

Decorator 只是一个语法糖,如果您过于急切,那么它就会使您搬起石头砸了自己的脚。decorator 其实就是一个至少具有一个参数的函数 —— 程序员要负责确保 decorator 的返回内容仍然是一个有意义的函数或方法,并且实现了原函数为使连接有用而做的事情。例如,下面就是 decorator 两个不正确的用法:



清单 5. 没有返回函数的错误 decorator
       
>>> def spamdef(fn):
... print "spam, spam, spam"
...
>>> @spamdef
... def useful(a, b):
... print a**2 + b**2
...
spam, spam, spam
>>> useful(3, 4)
Traceback (most recent call last):
File "", line 1, in ?
TypeError: 'NoneType' object is not callable

decorator 可能会返回一个函数,但这个函数与未修饰的函数之间不存在有意义的关联:



清单 6. 忽略传入函数的 decorator
       
>>> def spamrun(fn):
... def sayspam(*args):
... print "spam, spam, spam"
... return sayspam
...
>>> @spamrun
... def useful(a, b):
... print a**2 + b**2
...
>>> useful(3,4)
spam, spam, spam

最后,一个表现更良好的 decorator 可以在某些方面增强或修改未修饰函数的操作:



清单 7. 修改未修饰函数行为的 decorator
       
>>> def addspam(fn):
... def new(*args):
... print "spam, spam, spam"
... return fn(*args)
... return new
...
>>> @addspam
... def useful(a, b):
... print a**2 + b**2
...
>>> useful(3,4)
spam, spam, spam
25

您可能会质疑,useful() 到底有多么有用?addspam() 真的是那样出色的增强 吗?但这种机制至少符合您通常能在有用的 decorator 中看到的那种模式。







高级抽象简介

根据我的经验,元类应用最多的场合就是在类实例化之后对类中的方法进行修改。decorator 目前并不允许您修改类实例化本身,但是它们可以修改依附于类的方法。这并不能让您在实例化过程中动态添加或删除方法或类属性,但是它让这些方法可以在运行时根据环境的条件来变更其行为。现在从技术上来说,decorator 是在运行 class 语句时应用的,对于顶级类来说,它更接近于 “编译时” 而非 “运行时”。但是安排 decorator 的运行时决策与创建类工厂一样简单。例如:



清单 8. 健壮但却深度嵌套的 decorator
       
def arg_sayer(what):
def what_sayer(meth):
def new(self, *args, **kws):
print what
return meth(self, *args, **kws)
return new
return what_sayer

def FooMaker(word):
class Foo(object):
@arg_sayer(word)
def say(self): pass
return Foo()

foo1 = FooMaker('this')
foo2 = FooMaker('that')
print type(foo1),; foo1.say() # prints: this
print type(foo2),; foo2.say() # prints: that

@arg_sayer() 绕了很多弯路,但只获得非常有限的结果,不过对于它所阐明的几方面来说,这是值得的:

  • Foo.say() 方法对于不同的实例有不同的行为。在这个例子中,不同之处只是一个数据值,可以轻松地通过其他方式改变这个值;不过原则上来说,decorator 可以根据运行时的决策来彻底重写这个方法。

  • 本例中未修饰的 Foo.say() 方法是一个简单的占位符,其整个行为都是由 decorator 决定的。然而,在其他情况下,decorator 可能会将未修饰的方法与一些新功能相结合

  • 正如我们已经看到的一样,Foo.say() 的修改是通过 FooMaker() 类工厂在运行时严格确定的。可能更加典型的情况是在顶级定义类中使用 decorator,这些类只依赖于编译时可用的条件(这通常就足够了)。

  • decorator 都是参数化的。或者更确切地说,arg_sayer() 本身根本就不是一个真正的 decorator;arg_sayer() 所返回的 函数 —— what_sayer() 就是一个使用了闭包来封装其数据的 decorator 函数。参数化的 decorator 较为常见,但是它们将所需的函数嵌套为三层。






迈进元类领域

正 如上一节中介绍的一样,decorator 并不能完全取代元类挂钩,因为它们只修改了方法,而未添加或删除方法。实际上,这样说并不完全正确。作为一个 Python 函数,decorator 完全可以实现其他 Python 代码所实现的任何功能。通过修饰一个类的 .__new__() 方法(甚至是其占位符版本),您实际上可以更改附加到该类的方法。尽管尚未在现实中看到这种模式,不过我认为它有着某种必然性,甚至可以作为 _metaclass_ 指派的一项改进:



清单 9. 添加和删除方法的 decorator
       
def flaz(self): return 'flaz' # Silly utility method
def flam(self): return 'flam' # Another silly method

def change_methods(new):
"Warning: Only decorate the __new__() method with this decorator"
if new.__name__ != '__new__':
return new # Return an unchanged method
def __new__(cls, *args, **kws):
cls.flaz = flaz
cls.flam = flam
if hasattr(cls, 'say'): del cls.say
return super(cls.__class__, cls).__new__(cls, *args, **kws)
return __new__

class Foo(object):
@change_methods
def __new__(): pass
def say(self): print "Hi me:", self

foo = Foo()
print foo.flaz() # prints: flaz
foo.say() # AttributeError: 'Foo' object has no attribute 'say'

change_methods() decorator 示例中,我们添加并删除了几个固定的方法,不过这是毫无意义的。在更现实的情况中,应使用上一节中提到的几个模式。例如,参数化的 decorator 可以接受一个能表示要添加或删除的方法的数据结构;或者由数据库查询之类的某些环境特性做出这一决策。这种对附加方法的操作也可以像之前一样打包到一个函 数工厂中,这将使最终决策延迟到运行时。这些新兴技术也许比 _metaclass_ 指派更加万能。例如,您可以调用一个增强了的 change_methods(),如下所示:



清单 10. 增强的 change_methods()
       
class Foo(object):
@change_methods(add=(foo, bar, baz), remove=(fliz, flam))
def __new__(): pass







修改调用模型

您将看到,有关 decorator 的最典型的例子可能是使一个函数或方法来实现 “其他功能”,同时完成其基本工作。例如,在诸如 Python Cookbook Web 站点(请参见 参考资料 中的链接)之类的地方,您可以看到 decorator 添加了诸如跟踪、日志记录、存储/缓存、线程锁定以及输出重定向之类的功能。与这些修改相关(但实质略有区别)的是修饰 “之前” 和 “之后”。对于修饰之前/之后来说,一种有趣的可能性就是检查传递给函数的参数和函数返回值的类型。如果这些类型并非如我们预期的一样,那么这种 type_check() decorator 就可能会触发一个异常,或者采取一些纠正操作。

与这种 decorator 前/后类似的情况,我想到了 R 编程语言和 NumPy 特有的函数的 “elementwise” 应用。在这些语言中,数学函数通常应用于元素序列中的每个元素,但也会应用于单个数字。

当然,map() 函数、列表内涵(list-comprehension)和最近的生成器内涵(generator-comprehension 都可以让您实现 elementwise 应用。但是这需要较小的工作区来获得类似于 R 语言的行为:map() 所返回的序列类型通常是一个列表;如果您传递的是单个元素而不是一个序列,那么调用将失败。例如:



清单 11. map() 调用失败
       
>>> from math import sqrt
>>> map(sqrt, (4, 16, 25))
[2.0, 4.0, 5.0]
>>> map(sqrt, 144)
TypeError: argument 2 to map() must support iteration

创建一个可以 “增强” 普通数值函数的 decorator 并不困难:



清单 12. 将函数转换成 elementwise 函数
       
def elementwise(fn):
def newfn(arg):
if hasattr(arg,'__getitem__'): # is a Sequence
return type(arg)(map(fn, arg))
else:
return fn(arg)
return newfn

@elementwise
def compute(x):
return x**3 - 1

print compute(5) # prints: 124
print compute([1,2,3]) # prints: [0, 7, 26]
print compute((1,2,3)) # prints: (0, 7, 26)

当然,简单地编写一个具有不同返回类型的 compute() 函数并不困难;毕竟 decorator 只需占据几行。但是作为对面向方面编程的一种认可,这个例子让我们可以分离 那些在不同层次上运作的关注事项。我们可以编写各种数值计算函数,希望它们都可转换成 elementwise 调用模型,而不用考虑参数类型测试和返回值类型强制转换的细节。

对于那些对单个事物或事物序列(此时要保留序列类型)进行操作的函数来说,elementwise() decorator 均可同样出色地发挥作用。作为一个练习,您可尝试去解决如何允许相同的修饰后调用来接受和返回迭代器(提示:如果您只是想迭代一次完整的 elementwise 计算,那么当且仅当传入的是一个迭代对象时,才能这样简化一些。)

您 将碰到的大多数优秀的 decorator 都在很大程度上采用了这种组合正交关注的范例。传统的面向对象编程,尤其是在诸如 Python 之类允许多重继承的语言中,都会试图使用一个继承层次结构来模块化关注事项。然而,这仅会从一个祖先那里获取一些方法,而从其他祖先那里获取其他方法,因 此需要采用一种概念,使关注事项比在面向方面的思想中更加分散。要充分利用生成器,就要考虑一些与混搭方法不同的问题:可以处于方法本身的 “核心” 之外的关注事项为依据,使 方法以不同方式工作。





回页首


修饰 decorator


在结束本文之前,我想为您介绍一种确实非常出色的 Python 模块,名为 decorator,它是由与我合著过一些图书的 Michele Simionato 编写的。该模块使 decorator 的开发变得更加美妙。decorator 模块的主要组件具有某种自反式的优雅,它是一个称为 decorator() 的 decorator。与未修饰的函数相比,使用 @decorator 修饰过的函数可以通过一种更简单的方式编写。(相关资料请参看 参考资料)。

Michele 已经为自己的模块编写了很好的文档,因此这里不再赘述;不过我非常乐意介绍一下它所解决的基本问题。decorator 模块有两大主要优势。一方面,它使您可以编写出嵌套层次更少的 decorator,如果没有这个模块,您就只能使用更多层次(“平面优于嵌套”);但更加有趣的是这样一个事实:它使得修饰过的函数可以真正地与其在元 数据中未修饰的版本相匹配,这是我的例子中没有做到的。例如,回想一下我们上面使用过的简单 “跟踪” decorator addspam()



清单 13. 一个简单的 decorator 是如何造成元数据崩溃的
       
>>> def useful(a, b): return a**2 + b**2
>>> useful.__name__
'useful'
>>> from inspect import getargspec
>>> getargspec(useful)
(['a', 'b'], None, None, None)
>>> @addspam
... def useful(a, b): return a**2 + b**2
>>> useful.__name__
'new'
>>> getargspec(useful)
([], 'args', None, None)

尽管这个修饰过的函数的确完成 了自己增强过的工作,但若进一步了解,就会发现这并不是完全正确的,尤其是对于那些关心这种细节的代码分析工具或 IDE 来说更是如此。使用 decorator,我们就可以改进这些问题:



清单 14. decorator 更聪明的用法
       
>>> from decorator import decorator
>>> @decorator
... def addspam(f, *args, **kws):
... print "spam, spam, spam"
... return f(*args, **kws)
>>> @addspam
... def useful(a, b): return a**2 + b**2
>>> useful.__name__
'useful'
>>> getargspec(useful)
(['a', 'b'], None, None, None)

这对于编写 decorator 更加有利,同时,其保留行为的元数据的也更出色了。当然,阅读 Michele 开发这个模块所使用的全部资料会使您回到大脑混沌的世界,我们将这留给 Simionato 博士一样的宇宙学家好了。



参考资料

学习

在ubuntu上安装 XAMPP 进行方便集成开发

转载自:http://www.ibm.com/developerworks/cn/linux/l-xampp/


XAMPP 简介

XAMPP 是一个功能全面的 AMPP (Apache、MySQL、PHP、Perl)软件包,这是 Linux 平台上可以使用的几种非商业 AMPP 中间件之一。采用这种紧密的集成,XAMPP 可以运行任何程序:从个人主页到功能全面的产品站点(虽然这仅仅用于开发目的;出于安全考虑,XAMPP 还不适于用在产品服务器上)。

XAMPP 实际上在以下几个方面大放光彩:

  • 易于安装和设置。
  • 包含很多有用的软件包,可以简化诸如生成流量报告和加速 PHP 内容之类的任务。
  • 已经在 SUSE、Red Hat、Mandrake、Debian Linux 发行版以及 Windows® 和 Solaris 上进行了完整的测试。

对于本文来说,我们将在 Mandrake Linux 10.0 上安装 XAMPP。现在我们首先看看 XAMPP 中提供的缺省软件包。

基本的软件包

基本的软件包包括系统、编程和服务器软件:

  • Apache,著名的 Web 服务器
  • MySQL,一种杰出、免费的开源数据库
  • PHP,一种编程语言(在撰写本文时版本为 4.3.8 和 5.0.1)
  • Perl,一种编程语言
  • ProFTPD,一个 FTP 服务器
  • OpenSSL,可以支持安全套接字层

图形软件包

XAMPP 包括以下与图形有关的软件包:

  • GD,“Graphics Draw”库
  • libpng,官方的 PNG 参考实现库
  • libjpeg,官方的 JPEG 参考实现库
  • ncurses,字符图形库

数据库软件包

如果没有以下的数据库软件包,怎么还能叫集成软件呢?

  • gdbm,标准的 UNIX® dbm 库的 GNU 实现
  • SQLite,一个相当小的、无需任何配置的 SQL 数据库引擎
  • FreeTDS,一个数据库,让 UNIX 和 Linux 程序可以访问 Microsoft® SQL 和 Sybase 数据库

XML 软件包

为了开发 XML 程序,XAMPP 应该包含以下软件包:

  • expat,一个 XML 解析器库
  • Salbotron,一个 XML 工具包
  • libxml,一个 XML C 解析器和 GNOME 工具包

PHP 软件包

为了开发 PHP 程序,XAMPP 应该包括以下软件包:

  • PEAR,PHP 库
  • 一个 pdf 类,可以使用 PHP 生成动态的 PDF 文档
  • TURCK MMCache,一个 PHP 性能增强器

其他软件包

最后,XAMPP 中包含了以下软件包来展示自己的强大功能:

  • zlib,一个压缩库
  • mod_perl,在 Apache 中嵌入了一个永久的 Perl 解释器
  • gettext,一个工具集,可以帮助 GNU 软件包生成多语言的消息
  • mcrypt,一个加密程序
  • Ming,一个 Flash (SWF) 输出库
  • Freetype2,一个软件前端引擎
  • IMAP C-Client,一个邮件编程 API

现在让我们讨论一下安装 XAMPP 的问题。





回页首


安装并作为守护进程运行

要安装 XAMPP,请从 Apache Friends Web 站点上下载最新的二进制文件(请参阅 参考资料 中的链接)。使用下面的命令将其解开到 /opt 目录中:

tar xvfz xampp-linux-1.4.7.tar.gz -C /opt

就是这样!XAMPP 现在已经被安装到 /opt/lampp 目录中了。之前安装在 /opt 目录中的内容都已经被覆盖了。如果您正在运行一个旧版本的 XAMPP,并且不想再次下载整个软件包,Apache Friends 中还提供了一个升级包来下载需要的软件包。

现在所有的软件都已经安装好了,让我们启动新的守护进程。将当前的工作目录切换到 /opt/lampp ( cd /opt/lampp)并输入下面的命令:

./lampp start

您应该会看到下面的结果:

Starting XAMPP for Linux 1.4.7...
XAMPP: Starting Apache with SSL (and PHP5)...
XAMPP: Starting MySQL...
XAMPP: Starting ProFTPD...
XAMPP for Linux started.

XAMPP 现在就启动并运行了。最好的验证方法是打开一个浏览器并在地址栏中输入 localhost,并按回车键。此时浏览器会被重定向到 XAMPP 的 welcome 页面。



图 1. XAMPP welcome 页面
XAMPP welcome 页面

点击左边导航栏中的 Status 链接,就可以看到必需的服务已经正确启动了。如果所有的服务都运行正常,您就会看到下面的页面:



图 2. Service status 页面
Service status 页面

恭喜!您现在已经安装和设置好了一个完整的 AMPP 开发环境了。现在让我们安装一个简单的应用程序来展示一下如何使用这种环境。





回页首


安装一个简单的应用程序

要利用 XAMPP 的基本特性,您需要一个简单的应用程序。最好的应用程序是一个在后端使用数据库的程序;并使用一个相当简单的数据库,其中包含了一个精心设计的表。

测试数据库包含一个只有一列的表。让我们按照测试程序的(计算机)传统,设计在我们的表中存放一条记录“Hello World!”。我们将使用一个 Perl 和 一个 PHP 脚本来访问这个数据库。这两个脚本都可以访问这个数据库,从中检索这行记录,并将其输出到屏幕上。

工具

我 们的数据库将使用 phpMyAdmin 来创建和管理,这是使用 PHP 编写的一个杰出的基于 Web 的 MySQL 管理工具。它有一个非常友好的用户界面,可以允许您处理各种复杂的任务,包括创建/删除/修改数据库和表,以及导出数据、管理关键字和处理 SQL 文件。phpMyAdmin 是一个杰出的工具,因为:

  • 它可以帮助初学者熟悉 MySQL,而不用使用命令行接口来处理这些任务。
  • 它允许高级用户更快更容易地执行简单的任务和例行的任务。
  • 当您希望为某些用户授权访问数据库而不想让他们完全访问 shell 时,对于这种情况非常有用。

创建数据库

要在 phpMyAdmin 中创建一个数据库,请遵循下面的步骤:

  1. 转换到 XAMPP 的 start 页面 (localhost)。
  2. 在左边导航栏的 Tools 下面选择 phpMyAdmin
  3. 在 phpMyAdmin 主页的 Create New Database 域中,输入 hello_world,并点击 Create

现在您必须在数据库中创建一个表,并指定该表中应该包含哪些字段(字段与列类似)。让我们将自己的表称为“hello_table”,并让它只包含一个字段,其中保存记录“Hello world!”。在 Name 文本域中输入 hello_table,并在 Fields 文本域中输入 1。输入完之后,点击 Go

现在应该执行创建数据库的最后一个步骤了:为列选择一个名字和一个数据类型定义。让我们选中“hello”并将其命名为“hello_column”;并在 Field 文本域中输入 hello_column

由于我们要在列中存储字符串“Hello World!”,因此其类型必须是 char,长度为 12 (字符串 "Hello World!" 的长度)。缺省类型 varchar 就足够了。在 Type 后面的 Length/Values 文本域中,输入 12,表示最大长度是 12 个字符。不用关心该页面中其他域的设置,继续点击 Save

如果一切正常,您应该会看到下面的界面:



图 3. Hello World 数据库摘要
Hello World 数据库摘要

现在让我们插入记录 "Hello World!"。点击 Insert 标签,并在 Value 文本域中输入 "Hello World!"。 Function 下拉列表在这个例子中可以保留不变。点击 Go,将 "Hello World!" 记录插入数据库中。

要确认记录已经成功插入数据库,请点击 Browse 标签。现在会显示 "hello world"。

脚本

现在后端软件已经启动并运行了,应该处理脚本部分了。我们将使用两个脚本,一个使用 Perl 编写,另外一个使用 PHP 编写。对于每个脚本来说,惟一的要求就是一个数据库连接、数据库访问权限以及在屏幕上输出检索到的行。



清单 1. 简单的数据库连接,以及在 PHP 中使用 PEAR::DB 进行检索
    

require_once 'DB.php'; // must be included in any script that uses PEAR::DB
// it is a huge security risk to store your database connection information
// in the same file as your code. We have done it here solely for the purpose
// of this example. Please store your database connection information in another
// file that is not in your document root directory and adequately protected.
// database connection information
$db_host = "localhost"; // hostname of the database server
$db_user = "root"; // database user's username
$db_pass = ""; // database user's password, nothing by default
$db_name = "hello_world"; // the name of the database to connect to
$db_type = "mysql"; // the type of database server.
// your data source name string. This contains the connection
// information for your database.
$dsn = "$db_type://$db_user:$db_pass@$db_host/$db_name";
// creates a database connection object or a database error
// object based on the success of the database connection.
$db = DB::connect($dsn, TRUE);
// if an error was encountered, the script exits with an error message
if (DB::isError($db)) {
die($db->getMessage());
}
// SQL query that you wish to use to query the database
$sql = "SELECT * FROM hello_table";
// query the database, store result in $result
$result = $db->query($sql);
// exits with an error message if the query was unsuccessful
if(DB::isError($result)){
die($result->getMessage());
}
// fetch rows from the database until no more rows exist.
// output the "hello_column" field of each row to the screen.
// once no more rows exist, exit with an error message.
while($row = $result->fetchRow(DB_FETCHMODE_OBJECT)){
if(DB::isError($row)){
die($row->getMessage());
}
print("

$row->hello_column

");
$result->free();
}
$db->disconnect(); //disconnect from the database

这 两个脚本都会连接到数据库上,并检索一行数据,并将该行输出到屏幕上。PHP 的数据库访问是使用 PEAR::DB 完成的,这是一个方便的数据库抽象层,不管数据库是如何实现的,它都可以使用相同的数据库访问代码。不幸的是,XAMPP 中并没有包含一个用于 Perl 的数据库抽象层。

存放脚本

因此,现在我们已经做好了所需的一切。数据库已经启动并运行了,并且已经有了两个测试用的脚本。现在需要做的工作是将这些脚本放到正确的地方。让我们快速了解一下 XAMPP 是如何存放在硬盘上的,如 清单 2 所示。

我 们现在感兴趣的目录是 /opt/lampp/htdocs/,也就是 Apache 的 Documents 目录。在 Web 站点的根目录中显示的任何 Web 页面和相关文件都位于这个目录中。由于我们现在能够看到 XAMPP 的 welcome 页面,因此这个目录中已经存在一些文件了。现在让我们快速了解一下这个目录的内容:(输入 ls /opt/lampp/htdocs):

drwxr-xr-x 2 root root 4096 Jan 24 2003 apache
-rwxr-xr-x 1 nobody root 163 Oct 31 2003 index.html
drwxr-xr-x 2 nobody root 4096 Sep 12 21:54 webalizer
drwxr-xr-x 5 root root 4096 Jun 15 06:24 xampp

正如您可以看到的一样,这个目录中早已存在一些文件了。让我们在这个目录中建立一个自己的目录 hello_world ( mkdir hello_world)来存放脚本。从现在开始,您就可以输入 localhost/hello_world 来访问 hello_world 目录中的所有文件了。现在,将这两个脚本保存到这个目录中。到此为止,所有一切都已经完成了!

测试应用程序

要测试这个应用程序,首先切换到浏览器中,输入 localhost/hello_world。您应该会看到下面的界面:



图 4. Hello World!
Service status 页面

恭喜!您已经设置好 XAMPP 上的一个应用程序了。





回页首


增强安全性

XAMPP 的目标是一个开发环境。这种配置为程序员提供了一种对工具集没有任何限制的自由控制能力。作为自由的结果,缺省的 XAMPP 安装是非常不安全的。例如,有些操作几乎无需登录。

对于 0.9.5 以及更新版本的 XAMPP 来说,您可以运行下面的命令来增强安全性:

/opt/lampp/lampp security

此时会给出一些提示说明现有的不安全的地方,您可以选择是否修复这个问题。虽然这样可以使 XAMPP 安装更加安全,但是您仍然不应当在产品服务器中使用 XAMPP。清单 3 列出了安全性提示:



清单 3. XAMPP 中的安全性提示
    

XAMPP: Quick security check...
XAMPP: Your XAMPP pages are NOT secured by a password.
XAMPP: Do you want to set a password? [yes] yes
XAMPP: Password:
XAMPP: Password (again):
XAMPP: Password protection active. Please use 'lampp' as user name!
XAMPP: MySQL is accessable via network.
XAMPP: Normaly that's not recommended. Do you want me to turn it off? [yes] yes
XAMPP: Turned off.
XAMPP: Stopping MySQL...
XAMPP: Starting MySQL...
XAMPP: The MySQL/phpMyAdmin user pma has no password set!!!
XAMPP: Do you want to set a password? [yes] yes
XAMPP: Password:
XAMPP: Password (again):
XAMPP: Setting new MySQL pma password.
XAMPP: Setting phpMyAdmin's pma password to the new one.
XAMPP: MySQL has no root passwort set!!!
XAMPP: Do you want to set a password? [yes] yes
XAMPP: Write the password somewhere down to make sure you won't forget it!!!
XAMPP: Password:
XAMPP: Password (again):
XAMPP: Setting new MySQL root password.
XAMPP: Setting phpMyAdmin's root password to the new one.
XAMPP: The FTP password is still set to 'lampp'.
XAMPP: Do you want to change the password? [yes] yes
XAMPP: Password:
XAMPP: Password (again):
XAMPP: Reload ProFTPD...
XAMPP: Done.





回页首


执行备份

因此,假设您的 XAMPP 安装已经启动并运行了几周了,并向其中输入了很多数据,那么您就应该防范出现硬盘崩溃的风险。您需要做哪些备份工作呢?

使用 XAMPP 非常简单。将工作目录切换到 /opt/lampp ( cd /opt/lampp) 中,并输入下面的命令:

./lampp backup

如果您已经设置了 MySQL 的 root 密码,那么在这个命令后面就要添加上 root 用户的密码。您应该会看到下面的内容:

Backing up databases...
Backing up configuration, log and htdocs files...
Calculating checksums...
Building final backup file...
Backup finished.
Take care of /opt/lampp/backup/xampp-backup-15-09-04.sh

要恢复以前的备份,请以 root 用户的身份运行下面的命令:

sh backupfilename

如果一切正常,您将看到下面的结果:

Checking integrity of files...
Restoring configuration, log and htdocs files...
Checking versions...
Installed: XAMPP 1.4.7
Backup from: XAMPP 1.4.7
Restoring MySQL databases...
Restoring MySQL user databases...
Backup complete. Have fun!
You may need to restart XAMPP to complete the restore.

重新启动 XAMPP ( cd /opt/lampp, ./lampp restart),恢复的数据应该可用了。





回页首


结束语

虽然这种集成解决方案软件是否可以完全与 J2EE 竞争,尚需时日来进行验证,但是最近的发行版 PHP 5.0 (主要改进包括完全的面向对象的支持)与 MySQL 数据库的共同快速增长已经证明了它在开发人员之间越来越流行。这意味着像 XAMPP 这种开放源码中间件在低端软件市场上还是有一定的存活空间的。



参考资料

  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文

  • Apache Friends 上下载 XAMPP,这是一个非盈利组织,目标是增强 Apache Web 服务器。该网站上有最新的 XAMPP 信息和发行版本。

  • PHP 简介 (developerWorks,2000 年 12 月) 可以引导您入门 PHP 脚本语言。当您阅读这篇文章时,只需在搜索域中输入“PHP”,即可查找 IBM 提供的许多丰富的 PHP 资源。

  • 更佳编程之路 系列文章 (developerWorks) 是一组优秀的系列文章,可让您更加深入地了解 Perl 语言。要想了解有关 Perl 的更多内容,请搜索 developerWorks 站点。

  • 将 PHP 应用程序连接到 Apache Derby (developerWorks,2004 年 9 月)和 使用 Apache Derby 开发 Perl 应用程序 (developerWorks,2004 年 10 月)这两篇文章是 PHP 和 Perl 开发人员必读的文章。

  • phpMyAdmin 项目 包含了很多有用的信息,并可以下载这个杰出的基于 Web 的 MySQL 管理工具。

  • Practical Unix & Internet Security (O'Reilly & Associates,1996) 是一本有关系统安全性各个方面的优秀参考书,内容涉及从用户管理到起草安全策略。

  • PHP.net 提供了一个在线的可搜索函数库,它对于查找有关 PHP 方法的详细信息和学习语言构造有很大的帮助。

  • The PHP Extension and Application Repository (PEAR) 提供了一些可以简化 PHP 编程的组件,包括非常流行的 PEAR::DB

  • 有关 MySQL 的帮助, MySQL reference manual 中包含了有关这个流行数据库各个方面的详细信息。

  • 请访问 Apache HTTP Server Project,可以找到有关 Web 的最流行 http 服务器的最新版本和信息。

  • developerWorks Linux 专区 中可以找到更多为 Linux 开发者准备的资源。

  • 从 developerWorks 的 Speed-start your Linux app 专区下载运行于 Linux 之上的 IBM 中间件产品的免费测试版本,其中包括 WebSphere® Studio Application Developer、WebSphere Application Server、DB2® Universal Database、Tivoli® Access Manager 和 Tivoli Directory Server,并可学习 how-to 文章和获得技术支持。

  • 通过参与 developerWorks blogs 来参与 developerWorks 社区的工作。

  • 在 Developer Bookstore 的 Linux 区域中购买有关 Linux 的打折书籍


关于作者


Nils-Erik Frantzell 目前在位于圣克鲁斯的加州大学学习计算机科学。他的兴趣包括 Linux、Web 编程(尤其是 PHP)、网络、开源技术以及一些计算机硬件。他的业余时间用于饲养一些食肉性的鱼和欣赏电子音乐。您可以通过 nfrantze@ucsc.edu 与 Nils-Erik 联系。