[转载]你现在的CSS水平处于什么等级?

mikel阅读(780)

[转载]你现在的CSS水平处于什么等级? – Jensen – 博客园.

CSS(层叠样式表),可能看过网站制作教程网基础教程的人都知道大概是什么回事.本文来测一下,你学习CSS现在处于怎么一个阶段或者说处在一个什么等 级.

本文总共将CSS学习者从低到高分为六个等级.快来看看你是在哪个等级.

第0级:CSS?什么CSS,是不是CS啊.那游戏我玩过呀.是个多人游戏呀

CSS? Isn’t that a multiplayer game?

有些人因为在找CS:S(Counter Strike: Source)这款游戏的资讯而进到#CSS网站。不必担心这些人,他们不可能制作太多网页,所以对网络也不会造成多大伤害。

第1级:CSS我知道啊.也用.我偶尔用它来移除连结的底线

CSS Yeah, I use it to remove underlines on links sometimes

和第0级的人不同,这些人学过HTML,也制作过几个简单的网站。他们只有在无法使用HTML制作出某些效果时,才会使用CSS,例如移除连结 的底线或者设定行高。这些人的网站通常规模不大也没什么访客,所以他们也不会对网络造成太大伤害。

第2级:不,我不喜欢div元素;表格好用多了!

No, I don’t like divs; tables are much easier to work with

他们听过使用div元素来设计网页这件事,也花了些时间学习CSS。不过他们很快就放弃了,觉得CSS太难而且支持度不佳,还是宁可用表格排 版。

注意!他们是危险人物!他们在这个领域已经待了一段时间,许多都是网站部门的主管。和他们接触是很重要的,提倡网络标准的人应该多多开导他们,这对 网络的意义非同小可。

第3级:是啊,听说它挺好的,不过我没用它因为……

Yes I’ve heard it’s good, but I can’t use it because of…

这些人虽然知道CSS的优点,不过总是基于某些原因而无法使用它,例如他们可能有第2级的上司,或者他们必须考虑到Netscape 4的使用者。

旧版的浏览器虽然不支持CSS,不过使用者还是可以看见完整的内容。而基于亲和力(accessibility)和易用性 (usability)的好 处,CSS可以为网站带来更多访客。把这些优点告诉第3级的开发人员,即使他们不是决策者,或许多少能对第2级的上司发挥点影响力吧。

第4级:CSS?喔!没错,我用div元素来排版

CSS? Oh! Yes, I use divs for all my layouts

在页面中使用过多的div元素反而是这群人的问题,他们会用#toprightredline或是#r5_c7(表示第5列第7栏)这样的方式 设定div元 素的id。即使可以通过XHTML 1.1的验证,这种排版方式却无法发挥CSS的优势。荧幕朗读软体(screen readers,视障者使用的浏览器)很难解译这些网页,旧版浏览器也会有同样的问题,网页的内容无法完整显示。而不良的class与id命名方式,也对 于版面的修改造成极大不便。

虽然第4级的人制作的网站仍然很糟,不过由于他们很容易接受新的观念,因此对网络造成的伤害较小。许多所见即所得(WYSIWYG)的编辑器制作出 充满div元素的原始码,可能也是误导这群人的原因。幸好这些编辑器已经逐渐改良了,希望这会有助于第4级的人继续往上提升。

第5级:我用CSS来设计,这比表格好多了,因为……

I use CSS for design, it’s better than tables because of…

第5级的人知道CSS的优点并乐于使用,虽然有时会遇到些问题,但并不严重。他们也能运用长期的CSS工作经验,与人辩论为什么要将网页的结构 与设计分开。我猜这篇文章大部分的读者是这一级的CSS开发人员,我想我自己也是。不过这还不是最好的……

第6级:哪个版本的CSS?是的,我知道啊。你有读过我的书关于……

What version of CSS? Yes, I do. Did you read my book about…

第6级的人致力于改良CSS,并且写了许多很棒的文章介绍它的新用法。其中有些人将W3C关于CSS的说明文件全部读完了,并且知道哪些功能在 哪个版本的浏 览器才有支持。他们是CSS初学者的典范,并且运用他们的影响力使网络更加进步。其中有许多人组成了Web Standards Project,如果你在他们的网站上面发现任何错误,那一定是有理由的,向他们请教之后你必能获得满意的解答。

不管你处于哪个等级.只要认识学习.但一定要认清楚.CSS网页布局与表现的分离是一定有好处的.

[转载]OCI编程历程

mikel阅读(1034)

[转载]OCI编程历程 – 一个壮族小伙的技术博客 – 博客园.

前几天和哥们聊天,谈到连接数据库及一些数据库调用接口的开发问题。那哥们直接来了一句:“那东西没什么搞头,就调用些函数,然后做些错误处理”……… 我很是郁闷,回想起来实习时第一个能拿得出手的程序就是对OCI10库,当时为了测试效果一个人在机房里呆了一个多月,每天不停的拔网线。后来还把这个封 装库写在简历中项目经历的第二项。虽然现在看起来封装得有点幼稚,但还不至于一文不值。把我憋个够!想想还是把它写下来吧。
PS:本篇主要对OCI编程进行一些入门介绍,还涉及一些非阻塞和即时客户端配置的内容,所以高手请绕行。本人水平有限可能存在很多错误。

一、问题

为什么要使用OCI?可以使用ODBC对oracle数据库进行连接啊。当然这在widows系统上一点问题都没有,但如果程序需要跨多个不同的平台使用 ODBC就有一定的问题。不是还有unixODBC和iODBC吗?……在unix平台上使用MS推出的东西进行开发还是让我这种转牛角尖的菜鸟程序员难 以接受。

实习时所在的部门一直使用OCI来访问oracle数据库,所有的版本是oci7.3。对!没看错一直使用的就是这个96年的oci版本。确实太老了!这 么多年没有换版本主要是没有人再去维护它,还有勉强可用;另一方面,就像我那哥们讲的那样,大家都觉得这东西没什么可以做的了。

一切事物都逃不过产生、发展和消亡的命运。而在事物消亡的过程中总能找到几个标志性的事件来见证这个过程。部门里使用的oci7.3的接口库也逃不出这个 规律:有一次在给某大领导演示公司产品前十几分钟,所有的演示用工作站都开好,静等领导的到来。这时几个同事在搬动机器的时候不小心把系统中唯一的数据库 服务器的网线碰掉了(单点运行就是不靠谱),导致所有数据库连接的工作站都阻塞了,演示用机像死机似地没有一点反应。这下子把大家忙坏了,赶紧把数据库服 务器的网线插上,重启工作站的对应进程。还好在领导来到的时候,所有演示用机都重新准备好了。这件事加速原有的oci7.3接口库退出历史的舞台。大概在 08年10月,老大给我分配了改造这个oci接口的任务,要求:1.使用新的oci版本,本来想用oci9,但后来发现oci9的一些版本不支持某些特殊 的功能(本文后面会提到),所以后面选用03年出的oci10;2.接口函数尽量兼容原有版本,这样别人更换版本的时候不需要修改太多。当然还要跨平台、 调用过程方便简洁等等等等;3.执行查询语句时,每次获取N行(可以由调用者设定)放入调用者指定的缓冲区直至取完,当不满N行时取实际的行数放入缓冲 区,并返回实际取到的行数;4.与数据库的连接断开后能返回错误,并提够重连机制。这个要求也算是在服务器短时间内不会发生变化的情况下,一种用客户端来 保证稳定性的妥协做法吧。因为能oci接口如果能检测连接断开,那么调用者就可以采取一些处理,比如在本地缓存数据库的操作,或者向使用者发出连接断开的 提示等。5.用业余时间完成。

二、OCI编程的一般过程

与OCI7.3中使用的宿主语言定义变量存储空间(很拗口,不用管它)的方式不同,OCI9以后已不再使用原有的变量结构来初始化及维护数据库的信息,而 改用句柄的形式来和Oracle数据库进行交互。将常用的句柄定义在一个结构内,方便程序维护:

1 typedef struct _OCI_HANDLE
2 {
3 OCIEnv     *phEnv; //环境句柄,要使用oracle数据库, 必须首先获得环境句柄
4 OCISvcCtx  *phService; //oracle的服务句柄,也可以说是连 接句柄。
5 OCIError   *phErr; //oracle的错误句柄,可以获取错误 信息
6 OCIStmt    *phStmt; //oracle的语句描述句柄
7 OCIServer  *phServer; //Oracle 的服务器句柄
8 OCISession *phSession; //Oracle会话句柄
9 }OCIHANDLE, *LPOCIHANDLE;

OCI9编程的一般步骤有:初始化环境句柄、生成其他各类句柄、建立数据库连接进行登录、执行SQL语句,对返回的结果进行处理、终止用户会话,断开连 接,释放各种句柄。

image 上图给出OCI初始化的一个过程,OCI能初始化成功的前提当然是系统中已经安装或设置了Oracle的client端(在本文第四节有介绍)。其中步骤 (3)到(7)都分别调用OCIHandleAlloc()函数进行分配,顺序可以不同,它们都只依赖环境句柄;步骤(1)和(2)可以使用 OCIEnvCreate()函数替换掉,这两种的初始化OCI环境的方法在不同的使用条件下是不同的,一般建议使用OCIEnvCreate()代替 OCIInitialize()和OCIEnvInit(),因为OCIInitialize()和OCIEnvInit()主要是为了 backwards-compatible。而如果是编写DLL更是应该使用OCIEnvCreate()函数,user‘guide是这样说的:

If you are writing a DLL or a shared library using OCI library then this call should definitely be used instead of OCIInitialize() and OCIEnvInit() call.

OCI各句柄初始化完毕后,接下来就是连接数据库,如下图:

image

数据库连接好后可以执行SQL语句:一条SQL语句在OCI应用程序中的执行步骤一般如下:(1)准备SQL语句。(2)在SQL语句中绑定需要输入到 SQL语句中的变量。(3)执行SQL语句。(4)获取SQL中的输出描述。(5)定义输出变量。(6)获取数据。具体过程及过程中调用的函数如下图所 示。对于SQL中的定义语句(如CREATE,DROP)和控制语句(如GRANT,REVOKE),由于没有数据的输入输出,只需要图2中第一步和第三 步即可。操作语句(如INSERT,DELETE,UPDATE)则需要执行前三步。而查询语句(如SELECT)不仅可能有数据输入,而且也有数据的输 出,因此需要执行六个步骤。

image OCI编程的一般过程还是很清晰的,流程图都是一条线………

三、单次查询返回多行结果的实现

设计的时候老大要求要像原有接口库那样一次查询返回多行,然后再在本地进行处理,以减少对数据库的访问。这本来是一个很正常的要求,但后面看了好些开源的 OCI封装,发现它们的demo里都没有给出如何fetch多行……… 比如写的比较好的ocilib,demo中就没有给出(至少是以前的版本没给出,现在就不知道了),在写完这个OCI接口库大概半年后,再看ocilib 的代码OCIDefineByPos()函数时,发现倒数第三第四个参数都是指针,说明可以fetch多行。进而发现ocilib可以通过 OCI_SetFetchSize()函数来设置查询返回的行数。但为什么不在demo里给一个示例呢?就连该版本的文档里也没有这个函数的说明。很奇 怪!没办法还是自己动手丰衣足食,使劲啃user’guide。

需要fetch多行,首先要考虑执行select语句后,接收到数据放在什么地方?当然是放在缓冲区里了,在OCI里通过不同的变量函数绑定来告诉 oracle client把从数据库取到的数据存放在什么地方。这里使用OCIDefineByPos()函数。下面以每次取100行为例给出具体步骤:

1. 分配足够大的缓冲区m_pData = new unsigned char[m_DataLen * 100]。m_DataLen表示数据库表中每一行的长度(各个列长度之和),这样需要使用unsigned作Buffer,因为如果使用有符号char 则取带时间的表会有问题。

2. 根据各列的长度来定义各列在缓冲区中的位置:

01 OCIDefineByPos(m_hOCI.phStmt, //语句句柄
02 &(m_vecColInfo[i].phdefine),//定义句柄
03 m_hOCI.phErr,
04 i+1, //列序号
05 (ub1 *)(&(m_pData[pos])), //各列的位置pos等于当前列之前各列长度和乘以100
06 m_vecColInfo[i].collen, // 对应列的长度 SQLT_STR,
07 (m_vecColInfo[i].indp), // 指示器,因为每次最多要取100行,所以indp应设为维数为100的数组。
08 (m_vecColInfo[i].rlenp), // 返回数据的真实长度,这里也应把rlenp设为维数100的数组
09 0,
10 OCI_DEFAULT));

m_vecColInfo为保存各列信息的vector。值得注意的是OCIDefineByPos()的第八和第九个参数:第八个参数是指示器参数,在 OCIStmtFectch后只是所取的对应数据是否完整(0表示完整),由于要取100行,则在m_vecColInfo中每一个列元素对应的结构中都 应定义indp[100]的数组。第九个参数用于返回所取数据的实际长度,因此也需要在一个列元素的结构体中定义rlenp[100]的数组。还有一个需 要注意的是第四个参数里的pos,pos用于指定该列保存在Buffer中的起始位置。如下表是数据库中某表,执行select查询该表前100行后,数 据在缓冲区m_pData中保存数据的形式如图4:

CarKey MakeKey ModelKey ColorKey Year
1 1 1 2 2003
2 2 1 3 2005
3 2 1 2 2005
……. ……. …….. …….. ………
100 2 1 1 2006

image 上图可以看到OCI在fetch多行时,先将第一列的100行数据放入m_pData中,然后以列为单位每次取100行放入m_pData。因此pos变 量的赋值应写为:pos +=  100 * (m_vecColInfo[i-1].collen); 其中collen代表该列的长度。

3. 获取数据:

1 OCIStmtFetch(m_hOCI.phStmt,
2 m_hOCI.phErr,
3 100,//每次取100行的数据
4 OCI_FETCH_NEXT,
5 OCI_DEFAULT);

第三个参数设置为100后,执行OCIStmtFetch完毕后数据就填充到缓冲区中。这里需要注意的是最后一个fetch,因为最后一次fetch时数 据库表中往往已经不足100行,所以每次执行OCIStmtFetch()函数完毕要需要检查其返回值,当返回值为OCI_NO_DATA时使用:

1 OCIAttrGet(m_hOCI.phStmt,
2 OCI_HTYPE_STMT,
3 (dvoid *) &row_fetched,
4 (ub4 *) NULL,
5 (ub4) OCI_ATTR_ROWS_FETCHED,
6 m_hOCI.phErr);

row_fetched将返回剩下的行数,倒数第二个参数为OCI_ATTR_ROWS_FETCHED,在oci.h中是这样定义的:

#define OCI_ATTR_ROWS_FETCHED  197 /* rows fetched in last call */

在oci10中这里没有任何问题,但在一些较早的oci9版本中找不到OCI_ATTR_ROWS_FETCHED的定义……… 也就是说无法fetch多行?!迫不得已只能用oci10。可能ocilib在demo中没有fetch多行的示例也是出于这个考虑吧。

四、Oracle即时客户端(instantclient)的配置

过去使用OCI需要安装oracle的客户端,Oracle的普通客户端一般都很庞大,Windows平台下的客户端就有700M。Oracle公司在 10g版本后推出了大小只有30M的InstantClient(即时客户端)作为oracle的访问客户端。不需要安装就可以访问Oracle的服务 器。

Windows平台下instantclient的配置和使用:

下面以C:\Oracle为例介绍具体的配置过程。
1.将instantclient的basic包及sqlplus包中所有文件解压至C:\Oracle。
2.配置系统的环境变量:

• 将 C:\Oracle 添加到 PATH 中(位于其他 Oracle 目录之前)。例如,在 Windows 2000 上,依次单击“开始”->“设置”->“控制面板”->“系统”->“高级”->“环境变量”,编辑系统变量列表中的 PATH。WindowXP上,右击“我的电脑”->“高级”->“环境变量”。
• 添加用户环境变量 TNS_ADMIN 设置为C:\Oracle。
• 设置必要的 Oracle 全球化语言环境变量, 添加用户环境变量NLS_LANG 中文对应的字符集是 SIMPLIFIED CHINESE_CHINA.ZHS16GBK

3. 一共设置以下三个环境变量(以解压缩目录C:\Oracle为例)环境变量名 变量值

path C:\Oracle
TNS_ADMIN C:\Oracle
ORACLE_HOME C:\Oracle (可选)
NLS_LANG SIMPLIFIED CHINESE_CHINA.ZHS16GBK

4. tnsnames.ora和sqlnet.ora文件,这两个文件可以在所要访问的Oracle数据库服务器的$ORACLE_HOME/network /admin目录下找到,把tnsnames.ora中的服务器主机名改为ip地址即可。需更改时注意备份原来的文件。
5. 配置完毕后进入C:\Oracle运行sqlplus.exe登陆对应的数据库测试是否设置正确。在windows下使用instantclient时, 需要将instantclient的sdk包中的include和lib加到工程中。

Unix平台下instantclient的配置和使用:

本例中使用solaris_x86_10.2.0.2为客户端
1. 将instantclient_solaris_x86_10.2.0.2中的basic、sqlplus和sdk解压至同一目录,用chmod将该目录 下的所有文件设为可读写,比如:chmod –R 777 ./*

2. 配置环境变量:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/ychellboy/instantclient_10_2/
ORACLE_HOME=/home/ychellboy/instantclient_10_2/
export TNS_ADMIN=/home/ychellboy/instantclient_10_2/
可将上述命令写入一个XXX.sh文件。

3. tnsnames.ora和sqlnet.ora文件,这两个文件可以在所要访问的Oracle数据库服务器的$ORACLE_HOME/network /admin目录下找到,把tnsnames.ora中的服务器主机名改为ip地址即可。
4. 配置完毕后进入ORACLE_HOME指定的目录运行sqlplus.exe登陆对应的数据库测试是否设置正确。
在solaris下使用instantclient时需将链接库定位至ORACLE_HOME下,链接libclntsh打头的库文件即可。

五、instantclient的Bug

在开发时,最早下载InstantClient for win32 Version 10.2.0.5版,但怎么配置程序都无法初始化OCI的环境,错误发生在OCIInitialize()函数,换成OCIEnvCreate() 同样有错,设断点调试时报的错误是:弹出对话框“User breakpoint called from code at 0x…….”如下图所示;

image

同时Debug窗口输出的错误是:“HEAP[testlib.exe]: Invalid Address specified to RtlFreeHeap( 00140000, 0014F390 )”,下图所示:

image 都在还没初始化OCI怎么就溢出了?开始以为是instantclient没有正确配置,但sqlplus是可以使用的。然后怀疑是程序写错了,但使用普 通的oracle9i的客户端程序又能正确运行。期间还把VC6换成VS2005,问题依然没有解决。在快要放弃的时候换了InstantClient for win32 Version 10.1.0.5版,一试就通,原来是被oracle耍了。我现在还保留着10.2.0.5版,有兴趣玩一下的站内联系我。

六、连接断开的错误处理

据说自从OCI7.3后,OCI的连接可以设置成非阻塞模式。本文第二节可以看到到调用OCI函数和数据建立会话后可以使用OCIAttrSet()函数 将会话设置为费阻塞模式,但我没在user‘guide里找到有专门讲那些函数会受到影响的章节……(可能我看得不够仔细)?不知道那些函数操作会受到连 接断开的影响,那么即使设置了非阻塞模式也不知道在哪进行错误处理啊!没办法只能自己动手挨个函数试………
经过多次断网测试后得出以下函数将受到连接断开的影响,注意在windows下拔开网线后不管设置成阻塞或非阻塞这些函数都能返回并给出错误码。

Windows下:

1) OCIServerAttach:错误码12560,错误信息“TNS协议适配器错误”
2) OCISessionBegin:错误码12571,错误信息“TNS包写入程序失败”
3) OCIStmtExecute:如果在此函数执行前断网则返回错误码12571,错误信息“TNS包写入程序失败”,如果在此函数第一次执行(返回 OCI_STILL_EXECUTING)到第二次执行之间断网则返回错误码03113,错误信息“通信信道的文件结束”
4) OCIStmtFetch:错误码12571,错误信息“TNS包写入程序失败”
知道那些函数会受到断网影响后,处理起来就比较简单,即增加对这四个函数返回失败时的错误码判断,在断网时返回相应的错误返回给接口调用者, 由调用者选择处理方法。这种通过错误码进行处理的方法并不是长久之计,因为如果Oracle改变所返回的错误码,或者是在不同widows版本下返回的错 误码不一致则错误处理失效。不过windows并不是我们的主用系统所以就得过且过了^_^

Unix下:

Unix下断网情况和windows的情况相差很大,在unix下OCIServerAttach连接建立成功后,将此会话设置为阻塞则真的阻 塞!windows下即使设置成阻塞,断网发生时照样返回错误信息。unix下设置为非阻塞则情况又不一样。下面的函数带①表示会话设置为阻塞,断网后会 出现的情况。带②则表示会话设置为非阻塞,断网后会出现的情况。①②则表示阻塞、非阻塞情况都一样。
1)OCIStmtExecute() ===》① 无返回死等,检测不出断网,网络恢复后可正确执行(因为OCI用TCP做连接,可能也会有超时的时间) ② 执行时返回OCI_STILL_EXECUTING
2)OCIReset() ===》①② 阻塞死等
3)OCITransCommit() ===》①② 阻塞
4)OCIStmtFetch() ===》① 阻塞 ② 返回OCI_STILL_EXECUTING
5)OCISessionEnd() ===》①② 返回错误ORA-03127
6)OCIServerDetach() ===》①② 无影响可返回
7)OCIServerAttach() ===》①② 阻塞3~5分钟后返回错误ORA-12170
可以看到OCIServerAttach()和OCITransCommit()函数是一定阻塞的,不管会话有没有设置成非阻塞模式。我想 OCIServerAttach()函数里应该会调用到connect(),为什么Oracle就不做一个非阻塞的connect呢?搞不懂。如果要进行 断网的保护,那么在实现该OCI接口库时,使用到这两个函数的接口函数就应该放到子线程里进行调用。在主线程里timewait子线程,一旦子线程操作超 时就把它Terminate或cancel掉,然后返回连接断开的错误给调用者。这样干似乎很危险啊,查看了一下内存,发现在Solaris平台下每次打 断OCIServerAttach()函数后会产生60K的内存泄露。

终于写完了,托了好几天。接着闭关去!
References:
[1]Oracle® Call Interface Programmer’s Guide 10g Release 1(10.1), Part No.B10779-01, December 2003

[转载]操作PDF文档功能的相关开源项目探索iTextSharp 和PDFBox

mikel阅读(1246)

[转载]操作PDF文档功能的相关开源项目探索——iTextSharp 和PDFBox – 无痕客 – 博客园.

很久没自己写写心得日志与大家分享了,一方面是自己有点忙,一方面是自己有点懒,没有及时总结。因为实践是经验的来源,总结是提升的基础,所以 无论怎样,自己都该反省一下。今天我主要是研究学习了两个PDF文档的相关类,iTextSharp 和PDFBox。我研究出发点是实现PDF文档的检索,需要提取PDF文档中的文字内容,然后通过正则匹配实现搜索。

类似 Windows Search的文件搜索系统》中介绍的文件检索方法是很不错的,但它里面对PDF中的中文检索不支 持,因为里面调用的iTextSharp不能很好地支持英文,PdfReader类的GetPageContent()方法无法正常返回中文字符,经我测 试,并非简单的编码问题。所以,急需能够从PDF中提取text功能。

我首先学习iTextSharp.dll 下载:http://sourceforge.net/projects/itextsharp/ 这里面有很多输出PDF文档的简单例子(下载iTextSharp例子),在学习中发现,不支持中文内容输出。在网上搜索相关内容发现,原来是缺少字体库。 有两种方法解决:

1.自己指定系统的字体库,创建PDF中使用的字体。参见:http://unruledboy.cnblogs.com/Skins/ChinaHeart/Controls/archive/2005/08/30/225984.html

Document document = new Document(PageSize.A4,50, 50, 50, 50);
try
{
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(“Chap11.pdf”, FileMode.Create));

//下面是创建PDF文档加密的
//writer.SetEncryption(PdfWriter.STRENGTH40BITS,”654321″, “654321”, PdfWriter.AllowCopy);
document.Open();

//指定字体库,并创建字体
BaseFont baseFont = BaseFont.CreateFont(
“C:\\WINDOWS\\FONTS\\SIMHEI.TTF”,
BaseFont.IDENTITY_H,
BaseFont.NOT_EMBEDDED);
iTextSharp.text.Font font = new iTextSharp.text.Font(baseFont, 9);

//指定输出内容的字体

document.Add(new Paragraph(” This document is Top Secret! “, font));
document.Close();
}
catch (Exception de)
{
Console.WriteLine(de.StackTrace);
}

2.从http://sourceforge.net/projects/itextsharp/ 下载扩展字体库 iTextAsianCmaps.dll 和iTextAsian.dll,支持亚洲字体。

下载界面如下:

/// <summary>
/// 创建中文字体(实现中文)
/// </summary>
/// <returns></returns>
public static iTextSharp.text.Font CreateChineseFont()
{
BaseFont.AddToResourceSearch(“iTextAsian.dll”);
BaseFont.AddToResourceSearch(“iTextAsianCmaps.dll”); //”STSong-Light”, “UniGB-UCS2-H”,
BaseFont baseFT=BaseFont.CreateFont(“STSong-Light”, “UniGB-UCS2-H”, BaseFont.EMBEDDED);

iTextSharp.text.Font font = new iTextSharp.text.Font(baseFT);
return font;
}

“UniGB-UCS2-H” “UniGB-UCS2-V”是简体中文。 “STSong-Light”是字体名称。BaseFont.EMBEDDED是将字体嵌入文档内。

其次,我接下来尝试在使用iTextSharp读对象类时,指定字体库,可是很遗憾没有相应方法。请参照:http://www.cnblogs.com/diction/articles/1120984.html (提 取文本不支持中文)而且,即使有也很不灵活,因为你不可能预知PDF文档中使用的字体,PDF文档中可能有多种字体。后来,搜索网页相关信息发现:原来iTextSharp的操作PDF文档优势是PDF文档的创建。

需求是学习和工作的动力

我的原始目标是找到PDF文档内容提取为文本的方法,我转向《How to parse PDF files》 该文章完整讲述了PDF文档提取文本的方法和整个解决过程 思路,我会单独转载该文章,希望不能访问国外网的网友也能看到。PDFBox的下载http://sourceforge.net/projects/pdfbox/files/ 下 载解压后里面内容很丰富,

所有需要的dll都包含在Bin文件夹里面

“PDFBox is a Java PDF Library. This project will allow access to all of the components in a PDF document. More PDF manipulation features will be added as the project matures. This ships with a utility to take a PDF document and output a text file. ”

PDFBox是个JAVA开源项目,里面使用IKVM.NET开源项目http://www.ikvm.net/ 支持JAVA类库在.NET中调用。

IKVM.NET is an implementation of Java for Mono and the Microsoft .NET Framework. It includes the following components:

  • A Java Virtual Machine implemented in .NET
  • A .NET implementation of the Java class libraries
  • Tools that enable Java and .NET interoperability

对IKVM.NET的学习,对以后在.NET下使用JAVA类库很有帮助,其实IKVM.Runtime.dll 就是封装了JAVA类库的运行环境。

需要添加的DLL有:FontBox-0.1.0-dev.dll、IKVM.GNU.Classpath.dll、 IKVM.Runtime.dll、PDFBox-0.7.3.dll

PDFBox使用实例代码如下:请参照:http://www.cnblogs.com/wuhenke/archive/2010/04/16/1713949.html

private static string parseUsingPDFBox(string filename)
{
PDDocument doc = PDDocument.load(filename);

PDFTextStripper stripper = new PDFTextStripper();

return stripper.getText(doc);
}

PDFBox功能很强大,有时间值得好好学习一下。

参考:

http://www.codeproject.com/kb/cpp/ExtractPDFText.aspx?df=100&forumid=47947

http://www.codeproject.com/KB/string/pdf2text.aspx

http://www.cnblogs.com/hardrock/

http://www.ikvm.net/

[转载]MVP模式在asp.net中的应用

mikel阅读(1046)

[转载]MVP模式在asp.net中的应用 – 奋斗的天空 – 博客园.

前段时间,由于项目中需要用到MVP模式,于是我便来博客园查了一下,发现博客园有关MVP模式的资料少之又少,加上本人在博客园潜水这么久, 也想出来透透气啦,从而产生了写博的冲动。整个项目做下来,也对MVP模式有了一定的了解,特写下这篇文章来做一个总结吧,希望对学习MVP模式的朋友有 所帮助。话不多说,直接上图:

但是本章的重点不是这张图,而是在ASP.NET项目中怎么去用MVP模式。如果您对MVP模式有所了解的话,那么接下来就要上菜啦。

下面就用一个view开始:

public interface IMvpView { }

这是一个最基本的View接口,也就是说我们的UI(page,control)会直接或间接的继承它,我们还可以在这个接口里定义一些属性和 方法,而这些属性和方法是在我们每个界面都会用到的。很简单吧!

接下来就是一个presenter的基础类:

public abstract class Presenter<TView> where TView : IMvpView { public TView View { get; set; } public virtual void OnViewInitialized() { } public virtual void Save() { } }

这是一个最基本的presenter class,我把它定义为一个抽象的范型类。这个类的内容也很简单,它有一个TView类型的View属性,注意这里的TView不应该是一个具体 View,而应该是一个View的抽象。它还包括两方法,OnViewInitialized()和Save(), 我都把它们定义为Virtual,是要在继承类中重载。其中OnViewInitialized()方法里主要执行一些当 (IsPostBack==false)的操作,当然你还可以增加一个OnViewLoad()方法,来执行当页面加载时的操作.

定义了一些最基本的,接下来我要定义一些东东继承它们。

接下来创建一个IPersonView,它继承自我们最基本的view接口IMvpView:

public interace IPersonView:IMvpView { IList<Person> Persons{get;set;}
void Save(); }

接下来我又创建了一个PersonPresenter类,它继承自Presenter抽象类

public class PersonPresenter : Presenter<IPersonView> { private readonly IPersonController _controller; public PersonPresenter(IPersonController controller) { _controller = controller; } public override void OnViewInitialized() { View.Persons= _controller.GetPersons(); } public override void Save() { //do something } }

等等,怎么会突然冒出个IPersonController,这个接口干嘛的?重点来啦,presenter凭什么可以承担起UI的所有逻辑, 就是因为有这个IPersonController接口,这个接口的主要职责是通过您的Data Layer获得presenter完成UI逻辑所需要的数据,它是presenter的强大靠山。在这个例子中,IPersonController获得 person列表,来给赋给View的Persons属性,当然还做一些保存的动作(Save()).

接下来我还要做一件很有意义的事情,就是创建一个抽象的基础页面类:

public abstract class ViewBasePage<TPresenter, TView> : Page,IMvpView where TPresenter : Presenter<TView> where TView : IMvpView { protected TPresenter _presenter; public TPresenter Presenter { set { _presenter = value; _presenter.View = (IMvpView)(object)this; } } }

所有UI都会继承这个类,虽然它现在所做的事情很简单(仅仅是做范例),当然你还可以加一些在其它界面都会用到的方法或者属性来增强这个基类。

在这个例子中,我没有去实现Data Layer和controller,当然这也不是本文的重点,我希望通过这篇文章,让学习MVP模式的朋友,能对MVP模式有一个新的认识。

[原创]百度排名日志分析

mikel阅读(1253)

LogParser的导入SQL Server的命令:

logparser -i:IISW3C "SELECT TO_LOCALTIME(TO_TIMESTAMP([date], [time])) as [logdate] , [s-sitename], [s-computername], [s-ip], [cs-method], [cs-uri-stem], [cs-uri-query], [s-port], [cs-username], [c-ip], [cs-version], [cs(User-Agent)], [cs(Cookie)], [cs(Referer)], [cs-host], [sc-status],[sc-substatus], [sc-win32-status], [sc-bytes], [cs-bytes], [time-taken] INTO IISLog FROM d:\logs\ex*.log WHERE TO_LOWERCASE (EXTRACT_EXTENSION(cs-uri-stem)) NOT IN (‘gif’;’jpg’;’png’;’bmp’;’ico’;’axd’)" -o:SQL -server:MIKEL\MIKEL -database:Logs -driver:"SQL Server" -username:sa -password:justdoit -createTable:OFF

Dos下通过Ping反查IP指向的域名命令如下:
ping -a 123.125.66.134

百度蜘蛛标示如下:

百度各个产品使用不同的user-agent:

产品名称 对应user-agent
无线搜索 Baiduspider-mobile
图片搜索 Baiduspider-image
视频搜索 Baiduspider-video
新闻搜索 Baiduspider-news
百度搜藏 Baiduspider-favo
百度联盟 Baiduspider-cpro
网页以及其他搜索 Baiduspider

1.视频\图片信息蜘蛛抓取IP段:61.135.168.44-61.135.168.50

2.js脚本抓取蜘蛛IP段:61.135.165.202-61.135.165.206

[转载]解决下载/上传大文件问题(IIS6)

mikel阅读(1074)

[转载]解决下载/上传大文件问题(IIS6).

Windows 2003,当在IIS6上下载(/上传)大文件时,

会出现错误(log 文件中):80004005 Response_Buffer_Limit_Exceeded。

原因:IIS6 有一个缺省的设置:AspBufferingLimit= 4194304 是4M。

解决办法:将AspBufferingLimit的值增大到合适的大小。

步骤:
1. 修改IIS设置,允许直接编辑配置数据库

管理工具->IIS管理器里,选择计算机,右键,选择属性,然后选中“Enable Direct Metabase Edit”.
2. 修改IIS配置文件

1). 先在服务管理器里关闭iis admin service服务

管理工具->服务->iis admin service->停止。

2). 用文本编辑器打开C:\Windows\System32\Inesrv\下的Metabase.xml文件 注意:修改文件之前请先      备份。

3). 修改对下载文件大小限制
找到AspBufferingLimit,把它修改为你所需的大小。
例如:AspBufferingLimit=”8388608″ (8M)
修改对上传文件大小限制
找到ASPMaxRequestEntityAllowed 把他修改为需要的值,默认为204800,即200K 把它修改为你所       需的大小。如:8388608(8M)
例如:AspRequestQueueMax=”8388608″

4). 然后开启www服务
管理工具->服务->World Wide Web Publishing Service->开启

备注:
也可以直接在控制台命令行运行 ADSUTIL.VBS更改此值。不用停止IIS。
例如改为8M:运行 “ADSUTIL.VBS SET W3SVC/AspBufferingLimit 8388608” 另外,可以在控制台命令行直接停止和启动IIS。

停止:“Net stop iisadmin /y”

启动:“Net start w3svc”

也可以使用IIS6 Resource Kit中的Metabase Explorer (MBExplorer.exe)(代替Metaedit 2.2)编辑。

IIS6 Resource Kit的下载地址:
http://support.microsoft.com/kb/840671
http://www.microsoft.com/downloads/details.aspx?FamilyID=56fc92ee-a71a-4c73-b628-ade629c89499&DisplayLang=en

IIS6命令行工具的说明:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/iissdk/html/5e7f8cde-4a01-42bd-acaf-f8f7d091ef7c.asp

[转载]升级到NVelocity1.1版本

mikel阅读(1134)

[转载]升级到NVelocity1.1版本 – 小草 – 博客园.

由于NVelocity项目太久没有升级了,虽然看到Velocity经常发布一些新的功能,但.net版本的修改似乎比较迟。以至于很少关注升级情况。由于前期使用这个模板引擎的时候发现对DataTable支持不太好,原先想自己修改一下源代码,但分析了一下源代码发现改不动,也没有精力去研究。(最 近越来越懒了^_^

今天看到Richie写的关于1.1的两篇文章发现新版本已经解决了我想要的 支持。真是太高兴了,随即结合《Castle NVelocity – 1.1整 理了一下相关的代码供大家参考。

原先使用0.4X版本的时候其实也可以使用DataTable,但就是有些麻烦,我也是经过反复的测试后终于想到一个办法来处理,作法如下:需要循环行记录的情 况下再循环列,然后根据列号把值写到变量里,相当的麻烦。

#foreach($Item in $dtSubSortList.Rows)

#set ($rownum = 0)

#foreach($value in $Item.ItemArray)

#set ($rownum = $rownum+1)

#if($rownum == 1)

#set($CATEGORY_ID = “$value”)

#end

#if($rownum == 2)

#set($CATEGORY_NAME = “$value”)

#end

#end

<tr> <td class=”daoh_1″><div class=”wenz_2″><a href=”$!{WebRoot}cms/listPage.aspx?categoryId=$!{CATEGORY_ID}&parent=$!{categoryid}”>$CATEGORY_NAME</a></div></td></tr>

#end

新版本的写法就非常的简单了:

#foreach($Item in $dtSubSortList.Rows)

<tr> <td class=”daoh_1″><div class=”wenz_2″><a href=”$!{WebRoot}cms/listPage.aspx?categoryId=$Item.CATEGORY_ID”>$Item.CATEGORY_NAME</a></div></td></tr>

#end

但现在不足的 之处就是还不支持索引的写法,如$Item[0] 或者 $Item[“字段名“]

我整理的部分代码里封装了 NVelocityHelper,并写一下模板页的基类PageBaseTemplate等内容,仅供大家参考。

PageBase.cs

这个属性可以通过一些扩展实现多级子站的模 板定制功能(大家可以自己思考一下,我只是使用了目录的方式进行处理,应该还有其它更好的方法)。

1.1版本的 使用说明在《Castle NVelocity – 1.1 》有详细的说明,非常感谢。

原代码及最新的组件都在这里: /Files/liubiqu/NVelocity1.1Demo.rar

代码内容:

由于时间关系还没有详细的研究,下列问题有待进一步测试:

1、 velocity.GetTemplate是否有提供一些缓存与优化的处理

2、 velocity.Evaluate的时候log的参数有什么用处及整 合到其它日志方法

3、在性能方 面有没有更好的处理方式。

[原创]ASP.NET MVC链接地址的中文信息编码

mikel阅读(746)


<%="/Systems/DealerSaleList?isNew=1&fromDate=" + this.dealerCondition.ShopName + "&finishDate=" + this.dealerCondition.Service+"&dealerName=" + System.Web.HttpUtility.UrlEncode(ds.DealerName, System.Text.Encoding.GetEncoding("UTF-8")) %>

[转载].NET基础 - 简单几句说说GC(垃圾回收器)

mikel阅读(893)

[转载].NET基础 – 简单几句说说GC(垃圾回收器) – 今天你开心么,朋友? – 博客园.

.NETFramework包含两大部分,其一为BCL(基础类库),其二为CLR(公共语言运行库),这里要说的正是CLR中的GCGarbage Collector),俗称垃圾 回收器。

我们不如先用正规的方法描述一下垃圾回收中的几个要点:

1 CLR创建对象时,发现CLR所控制的堆中的内存不足以创建该对象,触发GC进行垃圾收集。

2 等待当前所有.NET应用程序处于挂起状态下,才真正开始收集动作,并非马上执行,也没有办法立即执行!

3 为共享堆中所有被引用的对象建立白名单,同时将所有带有析构标志位的对象统一放置到FReachable红名单中(先要折磨一下再释放)。

4 开始释放,具体的形式呢就是把白名单中的对象统一移动到堆的底部,其他没有点到名的,就会被释 放掉啦,同时将堆指针更新到可用对象最高的那个位置。

5 现在来处理红名单中的哥几个,GC先执行这些对象中的析构函数,同时重置析构标志为已处理,然后等待他们的就是下一次的清理,在那之前这些哥们还都 在堆里。

下面再对上面的几个步骤做一下说明:

1 为对象创建析构函数的目的是为了释放掉非托管资源(即GC管不到的CLR外的,可以理解为OS资源),当然,我们也可以通过编写Dispose()方法来手动释放非托管资源,但不会释放掉堆中的资源。

2 不像C++中对析构函数的使用,.NET中应尽量少地使用析构函数,因为如果析构函数过多,我们必须至少调用两次GC回收,才能真正释放出资源。

3 我们可以通过编码为GC添加或减少内存压力,目的只有一个,就是借此来控制收集的时机。

4 充分考虑到GC收集的范围限制,在编写需要调用非托管资源的应用时,建议 提供Dispose()方法和析构函数两个手段,当然,我们可以通过使用公共代码的 方式,来保证两者的工作不会出现冲突。这样我们将获得灵活的处理能力。

5 同时,我们可以设定有关GC的一些操作特性,包括是否关闭多线程调用及是否对2代进行资源收集等等。

6 堆分为三代:012,其容量逐渐递增,但其活跃程度逐层递减,每次收集后,白名单中的哥们都会自动升级,很明显,级数越高,证明使用的时间 越长,越可能是全局的一些内容。

[转载]介绍一下我自己开发的全新Remoting技术。(本地调用远程代码)

mikel阅读(862)

[转载]介绍一下我自己开发的全新Remoting技术。(本地调用远程代码) – 美丽人生 – 博客园.

前言

——————

本文介绍了一种全新的调用远程代码的技术。参考了微软 的remoting、webservice。

基础知识

——————

先抛开具体的代码,如果要实现远程代码调用,一个最简 单的模型是:

1. 使用一个HttpHandler,当有请求的时候,调用对应的代码,返回。例如:

代码

class RemoteHandler : IHttpHandler, IReadOnlySessionState
{
public bool IsReusable
{
get
{
return true;
}
}

public void ProcessRequest(HttpContext context)
{
//这里创建实例RemotingGreeting

RemotingGreeting greeting
= new RemotingGreeting();


byte[] response = greeting.Helloworld();

//这里返回调用结果到客户端

context.Response.Clear();

context.Response.ContentType = application/octet-stream;

BinaryWriter writer = new BinaryWriter(context.Response.OutputStream);

writer.Write(response);

writer.Flush();

writer.Close();

context.Response.End();
}
}

2. 客户端使用Http去访问这个Handler,就实现了最原始的远程调用

这段代码,就实现了远程调用 RemotingGreeting这个类,获取方法Helloworld();的返回值。

那么,这个过程如何实现通用呢?如何实现框架化?首先 先看看实际代码的调用效果:

代码实例

——————

首先声明一个被远程调用的对象,RemotingGreeting. 以及一个接口IRemotingGreeing

代码

class RemotingGreeting : IRemotingGreeting
{
public string Greeting(string message)
{
return Hi! + message;
}
}

[Remote(Pixysoft.Framework.Remoting.Demo, Pixysoft.Framework.Remoting.Demo.RemotingGreeting)]//这里实际指定了接口具体实现的类的Assembly和Type
public interface IRemotingGreeting
{
string Greeting(string message);
}

然后本地实现远程调用:

代码

using System;
using System.Collections.Generic;
using System.Text;

namespace Pixysoft.Framework.Remoting.Demo
{
class testcase
{
public void test()
{
//指定了调用的入口点 url
string url = http://localhost:1300/Apis/remoting.asmx;

//创建本地调用的透明代理
IRemoteChannel<IRemotingGreeting> channel = RemotingManager.CreateRemoteChannel<IRemotingGreeting>(url);

//登录远程服务器
channel.Login(xxxxxx, xxxxxxxxx);

//远程调用
string greeting = channel.RemoteProxy.Greeting(pixysoft);

//登出
channel.Logout();

//打印结果,就是“Hi!pixysoft”
Console.WriteLine(greeting);
}
}
}

正文

——————

远程调用框架的思路是:

1. 本地创建一个透明代理(RealProxy.GetTransparentProxy())

2. 用户本地的请求,被透明代理序列化为XML

3. XML传递到服务器的Handler,被解析后,加载对应的对象(Spring? 动态加载)

4. Handler运行对象,获取返回值,再序列化为XML,返回本地。

5. 本地透明代理解析XML,获取返回值。

第一步,创建透明代理。请各位先阅读 一篇相关的文章:

http://www.cnblogs.com/zc22/archive/2010/02/22/1671557.html

这里贴出核心代码的一个例子:

代码

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting.Messaging;

namespace Pixysoft.Framework.TestDrivens
{
public class Mock<TInterface> : RealProxy
{
public Mock()
:
base(typeof(TInterface))
{
}

public TInterface Value
{
get
{
return (TInterface)this.GetTransparentProxy();
}
}

public override IMessage Invoke(IMessage msg)
{
IMethodCallMessage methodCall
= msg as IMethodCallMessage;

//我返回 int = 1

return new ReturnMessage(1, null, 0, null, methodCall);
}
}

public interface IMock
{
int Devide(int a, int b);
}

public class testrealproxy //测试代码在这 里!!!
{
public void test()
{
IMock mock
= new Mock<IMock>().Value;

Console.WriteLine(mock.Devide(1, 2));

//输出 = 1
}
}
}

这篇文章讲解了如何实现一个接口的透明代理。本质在

public override IMessage Invoke(IMessage msg)

这里,对用户调用的方法进行序列化操作。

第二步,调用的序列化。

上文透明代理通过以下代码获取了用户调用的方法反射

IMethodCallMessage methodCall = msg as IMethodCallMessage;

MethodInfo method = methodCall.MethodBase as MethodInfo;

这里,要对调用方法MethodInfo进行序列化。 当然,就是自己去建立一个MethodInfo的xml描述,例如:

代码

<method assembly=”Pixysoft.Framework.Remoting” type=”Pixysoft.Framework.Remoting.Core.RemotingHelloworld” method=”HelloWorld” parametercount=”4″>
<parameter type=”DateTime” parameter=”para1″>2010-4-12 下午 08:52:21</parameter>
<parameter type=”String” parameter=”para2″>2</parameter>
<parameter type=”Int32″ parameter=”para3″>12</parameter>
<parameter type=”IRemotingValue” parameter=”para4″ />
<return type=”IRemotingValue” />
</method>

这个是我实际建立的MethodInfo的xml描 述。如何建立就不说了吧,很简单,用StringBuilder去拼就行了。

第三步,httpHandler解析 XML,加载对象运行结果。

客户端通过HttpPost到服务端,服务端获取了 XML之后,只要根据对应的参数加载Assembly,然后获取对象即可。具体涉及到了一些反射的操作:

Assembly assembly = Assembly.LoadFrom(assemblyname);

Type type = assembly.GetType(typename);

MethodInfo method = type.GetMethod(methodname);

获取了MethodInfo之后,只要把参数放入,获 取返回值即可。

代码

//实例化一个对象

ConstructorInfo constructorInfo
=
type.GetConstructor(BindingFlags.Public
| BindingFlags.NonPublic | BindingFlags.Instance,
null, new Type[] { }, null);

object remoteObject = constructorInfo.Invoke(new object[] { });

//调用这个对象的方法 这里省略了如何获取parameters过程

object returnvalue = method.Invoke(remoteObject, parameters);

第四步 Handler序列化返回值 为XML,返回本地。

只要把returnvalue序列化为xml即可。具 体就不叙述了。

第五步 本地透明代理解析XML,获取返回值。

本地透明代理把序列化的returnvalue再反序 列化为对象即可,然后返回

return new ReturnMessage(returnvalue, null, 0, null, methodCall);

难点讲解

——————

1. 整个调用过程最难的地方在于序列化操作。因为微软不支持接口的序列化、不支持内部类的序列化。这里需要自己实现。

2. 其次最难的在于值类型的操作。因为值类型进入了RealProxy之后,全部被装箱成为了对象(object)。这个时候直接把对象返回会抛异常,因此需 要根据具体的method.ReturnType, 逐一用值类型解析返回。

3. 再次,就是动态加载问题。Assembly.LoadFrom会有很多问题,比如版本问题、路径问题。因此要实现一个事件

AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

实现了这个event之后,能够代码指定搜索 assembly的位置。具体代码我就不列举了。

后记

——————

写代码的过程,和拼装模型是一样的。只要我们手上的零 件越来越多,能实现的功能和效果就越来越多!