春天花会开

***********

统计

留言簿(4)

阅读排行榜

评论排行榜

2010年6月19日 #

Windows GDI、GDI+ 绘图 防闪烁

“闪烁”的原因是擦除背景(用背景色重新填充)与绘制前景图像之间有时间差,而且背景和前景颜色有差异,导致眼睛看上去好像在闪烁。
“闪烁”并不主要是因为GDI或GDI+效率低造成的。

解决这个问题需从两个方面入手:1.缩短(或消除)前后景绘图时间差,2.减少绘制次数
1.缩短(或消除)前后景绘图时间差
OnEraseBkgnd(CDC* pDC)
{
    return TRUE;
}

实际上背景填充是必须,否则前景图像与残留的背景混在一起非常杂乱,
这里取消的步骤,其实移到绘图过程了(见2.),合成一张完整图像。

2.减少绘制次数
采用“双缓冲”技术,先在内存缓冲区中完成绘图,再贴到屏幕上
另外如果缓冲图像内容不是变化的,应存为成员对象之类,不要每次去画
一般在OnDraw(CDC* pDC)中完成
///////////////////////////--GDI --////////////////////////////////////
int nWidth=1000;
int nHeight=1000;
CDC MemDC; //首先定义一个显示设备对象
CBitmap MemBitmap;//定义一个位图对象
//随后建立与屏幕显示兼容的内存显示设备
MemDC.CreateCompatibleDC(pDC); //这时还不能绘图,因为没有地方画 ^_^
//下面建立一个与屏幕显示兼容的位图,至于位图的大小嘛,可以用窗口的大小
//,也可以自己定义(如:有滚动条时就要大于当前窗口的大小,在BitBlt时决定拷贝内存的哪部分到屏幕上)

MemBitmap.CreateCompatibleBitmap(pDC,nWidth,nHeight);
//将位图选入到内存显示设备中
//只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上

CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap);
//先用背景色将位图清除干净,这里用原背景色作为背景
//你也可以用自己应该用的颜色

MemDC.FillSolidRect(0,0,nWidth,nHeight,pDC->GetBkColor());
//绘图
CBrush brush(RGB(0,255,0));
 for(int i=0;i<50;i++)
 {
  for(int j=0;j<80;j++)
  {
   //MemDC.Rectangle(10*j,10*i,9,9);
   CRect rc(10*j,10*i,10*j+8,10*i+8);
   MemDC.FillRect(&rc,&brush);
  }
 }
//将内存中的图拷贝到屏幕上进行显示
pDC->BitBlt(0,0,nWidth,nHeight,&MemDC,0,0,SRCCOPY);
//绘图完成后的清理
MemBitmap.DeleteObject();
MemDC.DeleteDC();


///////////////////////////--GDI+ --////////////////////////////////////
 Bitmap* buf=new Bitmap(2000,2000) ;
 Graphics gc(buf);//Graphics.FromImage(buf);
 //反锯齿
 //gc.SetSmoothingMode(SmoothingModeAntiAlias);
 SolidBrush bgbrush(Color(255,255,255,255));
 gc.FillRectangle(&bgbrush,0,0,2000,2000);//背景填充
 Pen      pen(Color(255, 0, 0, 255));
 SolidBrush sbrush(Color(255,0,255,255));
 for(int i=0;i<60;i++)
 {
  for(int j=0;j<60;j++)
   gc.FillRectangle(&sbrush,10*j,10*i,9,9);
 }
 Graphics G(pDC->GetSafeHdc()); 
 G.DrawImage(buf ,0,0);

 

posted @ 2010-06-19 16:09 春天花会开 阅读(2483) | 评论 (1)编辑 收藏

2010年6月9日 #

Visual studio 2008/2010 MFC程序Menu、Toolbar字体偏小解决办法

首先,这是一个MFC的Bug
http://connect.microsoft.com/VisualStudio/feedback/details/505466/mfc-visual-style-font-size-too-small-to-display-chinese-character-clearly-on-windows-xp

解决时间暂时还不确定,临时的方案如下:
App在InitInstance中加入:

LOGFONT logfont = {0};
:: SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logfont, 0);
afxGlobalData.SetMenuFont(&logfont,true);

注释:

字体的设置保存在一个全局变量afxGlobalData中,此变量定义AfxGlobals.h中。
AFX_GLOBAL_DATA中有一个SetMenuFont可以设定字体属性,影响Menu、Toolbar、Dock Pane等的caption字体。
但是这个设置对tooltip无影响,临时解决:在上面代码基础上在加入

if(afxGlobalData.fontTooltip.GetSafeHandle() != NULL)
 {
  ::DeleteObject(afxGlobalData.fontTooltip.Detach());
 }
 afxGlobalData.fontTooltip.CreateFontIndirect(&logfont);

posted @ 2010-06-09 08:49 春天花会开 阅读(2256) | 评论 (2)编辑 收藏

2009年7月13日 #

DC/DC的工作原理!

根据调整管的工作状态,我们常把稳压电源分成两类:线性稳压电源开关稳压电源

   

    线性稳压电源,是指调整管工作在线性状态下的稳压电源。而在开关电源中则不一样,开关管(在开关电源中,我们一般把调整管叫做开关管)是工作在开、关两种状态下的:开——电阻很小;关——电阻很大

     开关电源是一种比较新型的电源。它具有效率高,重量轻,可升、降压,输出功率大等优点。但是由于电路工作在开关状态,所以噪声比较大 通过下图,我们来简单的说说降压型开关电源的工作原理。如图所示,电路由开关K(实际电路中为三极管或者场效应管),续流二极管D储能电感L滤波电容C等构成。当开关闭合时,电源通过开关K、电感L负载供电,并将部分电能储存在电感L以及电容C中。由于电感L的自感,在开关接通后,电流增大得比较缓慢,即输出不能立刻达到电源电压值。一定时间后,开关断开,由于电感L的自感作用(可以比较形象的认为电感中的电流有惯性作用),将保持电路中的电流不变,即从左往右继续流。这电流流过负载,从地线返回,流到续流二极管D的正极,经过二极管D返回电感L的左端,从而形成了一个回路。通过控制开关闭合跟断开的时间(PWM——脉冲宽度调制),就可以控制输出电压。如果通过检测输出电压来控制开、关的时间,以保持输出电压不变,这就实现了稳压的目的。

 

 500)this.width=500" border="0">

在开关闭合期间,电感存储能量;在开关断开期间,电感释放能量,所以电感L叫做储能电感。二极管D在开关断开期间,负责给电感L提供电流通路,所以二极管D叫做续流二极管

 

 在实际的开关电源中,开关K由三极管或场效应管代替。当开关断开时,电流很小;当开关闭合时,电压很小,所以发热功率U×I就会很小。这就是开关电源效率高的原因。

 

看过完两个关于电源的FAQ后,大家可能对电源的效率计算还不了解。在后面的FAQ中,我们将专门给大家介绍。

摘自网络.

posted @ 2009-07-13 14:42 春天花会开 阅读(359) | 评论 (0)编辑 收藏

2009年5月16日 #

MySQL 备份和恢复

http://imysql.cn/mysql_backup_and_recover


作/译者:叶金荣,来源:http://imysql.cn,转载请注明作/译者和出处,并且不能用于商业用途,违者必究。

日期:2006/10/01

本文讨论 MySQL 的备份和恢复机制,以及如何维护数据表,包括最主要的两种表类型:MyISAMInnodb,文中设计的 MySQL 版本为 5.0.22。

目前 MySQL 支持的免费备份工具有:mysqldump、mysqlhotcopy,还可以用 SQL 语法进行备份:BACKUP TABLE 或者 SELECT INTO OUTFILE,又或者备份二进制日志(binlog),还可以是直接拷贝数据文件和相关的配置文件。MyISAM 表是保存成文件的形式,因此相对比较容易备份,上面提到的几种方法都可以使用。Innodb 所有的表都保存在同一个数据文件 ibdata1 中(也可能是多个文件,或者是独立的表空间文件),相对来说比较不好备份,免费的方案可以是拷贝数据文件备份 binlog,或者用 mysqldump

1、mysqldump

1.1 备份

mysqldump 是采用SQL级别的备份机制,它将数据表导成 SQL 脚本文件,在不同的 MySQL 版本之间升级时相对比较合适,这也是最常用的备份方法。
现在来讲一下 mysqldump 的一些主要参数:

  • --compatible=name

    它告诉 mysqldump,导出的数据将和哪种数据库或哪个旧版本的 MySQL 服务器相兼容。值可以为 ansi、mysql323、mysql40、postgresql、oracle、mssql、db2、maxdb、no_key_options、no_tables_options、no_field_options 等,要使用几个值,用逗号将它们隔开。当然了,它并不保证能完全兼容,而是尽量兼容。

  • --complete-insert,-c

    导出的数据采用包含字段名的完整 INSERT 方式,也就是把所有的值都写在一行。这么做能提高插入效率,但是可能会受到 max_allowed_packet 参数的影响而导致插入失败。因此,需要谨慎使用该参数,至少我不推荐。

  • --default-character-set=charset

    指定导出数据时采用何种字符集,如果数据表不是采用默认的 latin1 字符集的话,那么导出时必须指定该选项,否则再次导入数据后将产生乱码问题。

  • --disable-keys

    告诉 mysqldumpINSERT 语句的开头和结尾增加 /*!40000 ALTER TABLE table DISABLE KEYS */;/*!40000 ALTER TABLE table ENABLE KEYS */; 语句,这能大大提高插入语句的速度,因为它是在插入完所有数据后才重建索引的。该选项只适合 MyISAM 表。

  • --extended-insert = true|false

    默认情况下,mysqldump 开启 --complete-insert 模式,因此不想用它的的话,就使用本选项,设定它的值为 false 即可。

  • --hex-blob

    使用十六进制格式导出二进制字符串字段。如果有二进制数据就必须使用本选项。影响到的字段类型有 BINARY、VARBINARY、BLOB

  • --lock-all-tables,-x

    在开始导出之前,提交请求锁定所有数据库中的所有表,以保证数据的一致性。这是一个全局读锁,并且自动关闭 --single-transaction--lock-tables 选项。

  • --lock-tables

    它和 --lock-all-tables 类似,不过是锁定当前导出的数据表,而不是一下子锁定全部库下的表。本选项只适用于 MyISAM 表,如果是 Innodb 表可以用 --single-transaction 选项。

  • --no-create-info,-t

    只导出数据,而不添加 CREATE TABLE 语句。

  • --no-data,-d

    不导出任何数据,只导出数据库表结构。

  • --opt

    这只是一个快捷选项,等同于同时添加 --add-drop-tables --add-locking --create-option --disable-keys --extended-insert --lock-tables --quick --set-charset 选项。本选项能让 mysqldump 很快的导出数据,并且导出的数据能很快导回。该选项默认开启,但可以用 --skip-opt 禁用。注意,如果运行 mysqldump 没有指定 --quick--opt 选项,则会将整个结果集放在内存中。如果导出大数据库的话可能会出现问题。

  • --quick,-q

    该选项在导出大表时很有用,它强制 mysqldump 从服务器查询取得记录直接输出而不是取得所有记录后将它们缓存到内存中。

  • --routines,-R

    导出存储过程以及自定义函数。

  • --single-transaction

    该选项在导出数据之前提交一个 BEGIN SQL语句,BEGIN 不会阻塞任何应用程序且能保证导出时数据库的一致性状态。它只适用于事务表,例如 InnoDBBDB
    本选项和 --lock-tables 选项是互斥的,因为 LOCK TABLES 会使任何挂起的事务隐含提交。
    要想导出大表的话,应结合使用 --quick 选项。

  • --triggers

    同时导出触发器。该选项默认启用,用 --skip-triggers 禁用它。

其他参数详情请参考手册,我通常使用以下 SQL 来备份 MyISAM 表:

/usr/local/mysql/bin/mysqldump -uyejr -pyejr \
--default-character-set=utf8 --opt --extended-insert=false \
--triggers -R --hex-blob -x db_name > db_name.sql

使用以下 SQL 来备份 Innodb 表:

/usr/local/mysql/bin/mysqldump -uyejr -pyejr \
--default-character-set=utf8 --opt --extended-insert=false \
--triggers -R --hex-blob --single-transaction db_name > db_name.sql

另外,如果想要实现在线备份,还可以使用 --master-data 参数来实现,如下:

/usr/local/mysql/bin/mysqldump -uyejr -pyejr \
--default-character-set=utf8 --opt --master-data=1 \
--single-transaction --flush-logs db_name > db_name.sql

它只是在一开始的瞬间请求锁表,然后就刷新binlog了,而后在导出的文件中加入CHANGE MASTER 语句来指定当前备份的binlog位置,如果要把这个文件恢复到slave里去,就可以采用这种方法来做。

1.2 还原

mysqldump 备份出来的文件是一个可以直接倒入的 SQL 脚本,有两种方法可以将数据导入。

  • 直接用 mysql 客户端

    例如:

    /usr/local/mysql/bin/mysql -uyejr -pyejr db_name < db_name.sql
        

     

  • 用 SOURCE 语法

    其实这不是标准的 SQL 语法,而是 mysql 客户端提供的功能,例如:

    SOURCE /tmp/db_name.sql;
        

    这里需要指定文件的绝对路径,并且必须是 mysqld 运行用户(例如 nobody)有权限读取的文件。

2、 mysqlhotcopy

2.1 备份

mysqlhotcopy 是一个 PERL 程序,最初由Tim Bunce编写。它使用 LOCK TABLES、FLUSH TABLEScpscp 来快速备份数据库。它是备份数据库或单个表的最快的途径,但它只能运行在数据库文件(包括数据表定义文件、数据文件、索引文件)所在的机器上。mysqlhotcopy 只能用于备份 MyISAM,并且只能运行在 类UnixNetWare 系统上。

mysqlhotcopy 支持一次性拷贝多个数据库,同时还支持正则表达。以下是几个例子:

root#/usr/local/mysql/bin/mysqlhotcopy -h=localhost -u=yejr -p=yejr \
db_name /tmp (把数据库目录 db_name 拷贝到 /tmp 下)
root#/usr/local/mysql/bin/mysqlhotcopy -h=localhost -u=yejr -p=yejr \
db_name_1 ... db_name_n /tmp
root#/usr/local/mysql/bin/mysqlhotcopy -h=localhost -u=yejr -p=yejr \
db_name./regex/ /tmp

更详细的使用方法请查看手册,或者调用下面的命令来查看 mysqlhotcopy 的帮助:

perldoc /usr/local/mysql/bin/mysqlhotcopy

注意,想要使用 mysqlhotcopy,必须要有 SELECT、RELOAD(要执行 FLUSH TABLES) 权限,并且还必须要能够有读取 datadir/db_name 目录的权限。

2.2 还原

mysqlhotcopy 备份出来的是整个数据库目录,使用时可以直接拷贝到 mysqld 指定的 datadir (在这里是 /usr/local/mysql/data/)目录下即可,同时要注意权限的问题,如下例:

root#cp -rf db_name /usr/local/mysql/data/
root#chown -R nobody:nobody /usr/local/mysql/data/ (将 db_name 目录的属主改成 mysqld 运行用户)

 

3、 SQL 语法备份

3.1 备份

BACKUP TABLE 语法其实和 mysqlhotcopy 的工作原理差不多,都是锁表,然后拷贝数据文件。它能实现在线备份,但是效果不理想,因此不推荐使用。它只拷贝表结构文件和数据文件,不同时拷贝索引文件,因此恢复时比较慢。
例子:

BACK TABLE tbl_name TO '/tmp/db_name/';

注意,必须要有 FILE 权限才能执行本SQL,并且目录 /tmp/db_name/ 必须能被 mysqld 用户可写,导出的文件不能覆盖已经存在的文件,以避免安全问题。

SELECT INTO OUTFILE 则是把数据导出来成为普通的文本文件,可以自定义字段间隔的方式,方便处理这些数据。
例子:

SELECT * INTO OUTFILE '/tmp/db_name/tbl_name.txt' FROM tbl_name;

注意,必须要有 FILE 权限才能执行本SQL,并且文件 /tmp/db_name/tbl_name.txt 必须能被 mysqld 用户可写,导出的文件不能覆盖已经存在的文件,以避免安全问题。

3.2 恢复

BACKUP TABLE 方法备份出来的文件,可以运行 RESTORE TABLE 语句来恢复数据表。
例子:

RESTORE TABLE FROM '/tmp/db_name/';

权限要求类似上面所述。

SELECT INTO OUTFILE 方法备份出来的文件,可以运行 LOAD DATA INFILE 语句来恢复数据表。
例子:

LOAD DATA INFILE '/tmp/db_name/tbl_name.txt' INTO TABLE tbl_name;

权限要求类似上面所述。倒入数据之前,数据表要已经存在才行。如果担心数据会发生重复,可以增加 REPLACE 关键字来替换已有记录或者用 IGNORE 关键字来忽略他们。

4、 启用二进制日志(binlog)

采用 binlog 的方法相对来说更灵活,省心省力,而且还可以支持增量备份。

启用 binlog 时必须要重启 mysqld。首先,关闭 mysqld,打开 my.cnf,加入以下几行:

server-id	= 1
log-bin		= binlog
log-bin-index	= binlog.index

然后启动 mysqld 就可以了。运行过程中会产生 binlog.000001 以及 binlog.index,前面的文件是 mysqld 记录所有对数据的更新操作,后面的文件则是所有 binlog 的索引,都不能轻易删除。关于 binlog 的信息请查看手册。

需要备份时,可以先执行一下 SQL 语句,让 mysqld 终止对当前 binlog 的写入,就可以把文件直接备份,这样的话就能达到增量备份的目的了:

FLUSH LOGS;

如果是备份复制系统中的从服务器,还应该备份 master.inforelay-log.info 文件。

备份出来的 binlog 文件可以用 MySQL 提供的工具 mysqlbinlog 来查看,如:

/usr/local/mysql/bin/mysqlbinlog /tmp/binlog.000001

该工具允许你显示指定的数据库下的所有 SQL 语句,并且还可以限定时间范围,相当的方便,详细的请查看手册。

恢复时,可以采用类似以下语句来做到:

/usr/local/mysql/bin/mysqlbinlog /tmp/binlog.000001 | mysql -uyejr -pyejr db_name

mysqlbinlog 输出的 SQL 语句直接作为输入来执行它。

如果你有空闲的机器,不妨采用这种方式来备份。由于作为 slave 的机器性能要求相对不是那么高,因此成本低,用低成本就能实现增量备份而且还能分担一部分数据查询压力,何乐而不为呢?

5、 直接备份数据文件

相较前几种方法,备份数据文件最为直接、快速、方便,缺点是基本上不能实现增量备份。为了保证数据的一致性,需要在靠背文件前,执行以下 SQL 语句:

FLUSH TABLES WITH READ LOCK;

也就是把内存中的数据都刷新到磁盘中,同时锁定数据表,以保证拷贝过程中不会有新的数据写入。这种方法备份出来的数据恢复也很简单,直接拷贝回原来的数据库目录下即可。

注意,对于 Innodb 类型表来说,还需要备份其日志文件,即 ib_logfile* 文件。因为当 Innodb 表损坏时,就可以依靠这些日志文件来恢复。

6、 备份策略

对于中等级别业务量的系统来说,备份策略可以这么定:第一次全量备份,每天一次增量备份,每周再做一次全量备份,如此一直重复。而对于重要的且繁忙的系统来说,则可能需要每天一次全量备份,每小时一次增量备份,甚至更频繁。为了不影响线上业务,实现在线备份,并且能增量备份,最好的办法就是采用主从复制机制(replication),在 slave 机器上做备份。

7、 数据维护和灾难恢复

作为一名DBA(我目前还不是,呵呵),最重要的工作内容之一是保证数据表能安全、稳定、高速使用。因此,需要定期维护你的数据表。以下 SQL 语句就很有用:

CHECK TABLE 或 REPAIR TABLE,检查或维护 MyISAM 表
OPTIMIZE TABLE,优化 MyISAM 表
ANALYZE TABLE,分析 MyISAM 表

当然了,上面这些命令起始都可以通过工具 myisamchk 来完成,在这里不作详述。

Innodb 表则可以通过执行以下语句来整理碎片,提高索引速度:

ALTER TABLE tbl_name ENGINE = Innodb;

这其实是一个 NULL 操作,表面上看什么也不做,实际上重新整理碎片了。

通常使用的 MyISAM 表可以用上面提到的恢复方法来完成。如果是索引坏了,可以用 myisamchk 工具来重建索引。而对于 Innodb 表来说,就没这么直接了,因为它把所有的表都保存在一个表空间了。不过 Innodb 有一个检查机制叫 模糊检查点,只要保存了日志文件,就能根据日志文件来修复错误。可以在 my.cnf 文件中,增加以下参数,让 mysqld 在启动时自动检查日志文件:

innodb_force_recovery	= 4

关于该参数的信息请查看手册。

8、 总结

做好数据备份,定只好合适的备份策略,这是一个DBA所做事情的一小部分,万事开头难,就从现在开始吧!

posted @ 2009-05-16 22:01 春天花会开 阅读(123) | 评论 (1)编辑 收藏

2009年4月30日 #

[转]CListCtrl使用技巧--学习用

     摘要: 1. CListCtrl 风格
2. 设置listctrl 风格及扩展风格
3. 插入数据
4. 一直选中item
5. 选中和取消选中一行
6. 得到listctrl中所有行的checkbox的状态
7. 得到listctrl中所有选中行的序号
8. 得到item的信息
9. 得到listctrl的所有列的header字符串内容
10. 使listctrl中一项可见,即滚动滚动条
11. 得到listctrl列数
12. 删除所有列
13. 得到单击的listctrl的行列号
14. 判断是否点击在listctrl的checkbox上
15. 右键点击listctrl的item弹出菜单
16. item切换焦点时(包括用键盘和鼠标切换item时),状态的一些变化顺序
17. 得到另一个进程里的listctrl控件的item内容
18. 选中listview中的item
19. 如何在CListView中使用CListCtrl的派生类 阅读全文

posted @ 2009-04-30 11:20 春天花会开| 编辑 收藏

2008年7月31日 #

[转载]MIME邮件的编码方式

转自:http://book.csdn.net/bookfiles/402/10040214756.shtml

MIME邮件的编码方式

由于每个ASCII码字符只占用一个字节(8个bit位),且最高bit位总为0,即ASCII码字符中的有真正意义的信息只是后面的7个低bit位,而传统的SMTP协议又是基于ASCII码字符设计的,因此,一些基于传统SMTP协议设计的SMTP服务器在处理邮件内容时只取出每个字节中的7个低bit位进行处理,而将最高bit位忽略不计。显然,这样的SMTP服务器在处理包含有非ASCII码字符的邮件内容时,会出现严重的问题,这就限制了邮件中只能出现英文的ASCII码字符,而不能出现中文字符或二进制数据。

为了能够在邮件内容中包含中文、图像或声音等非ASCII字符的数据,人们想到了采用某种编码方式将非ASCII字符的数据转换成可打印的ASCII字符后再发送,邮件阅读程序则按照相应的解码方式从邮件中还原出原始数据即可,比较常用的两种邮件编码方式为BASE64和Quoted-printable。后来的扩展SMTP协议允许直接在邮件中传递二进制数据,而不用对它们进行邮件编码,人们将这种没有进行邮件编码的二进制数据的邮件内容称为8bit编码,为了与此相区别,人们将没有进行邮件编码的纯ASCII码字符的邮件称为7bit编码。MIME消息体的邮件编码方式通过MIME消息头中的Content- Transfer- Encoding头字段指定,每种邮件编码方式的介绍如下:

—  7Bit

指消息体内容全部是没有经过编码的ASCII字符。

—  8Bit

指消息体内容是没有经过编码的原始数据,且其中包含有非ASCII字符的数据。现在的邮件服务器基本上都支持8Bit编码,使用支持8Bit编码的邮件服务器可以简化邮件的处理过程。

—  BASE64

Base64是将二进制数据转换成可打印的ASCII字符的一种最常见的编码方式,它的基本原理是将一组连续的字节数据按6个bit位进行分组,然后对每组数据用一个ASCII字符来表示。6个bit位最多能表示26=64个数值,因此可以使用64个ASCII字符来对应这64个数值,这64个ASCII字符为:

"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

其中每个字符表示的数值就是该字符在上面的排列中的索引号,索引号从0开始编号。假设在内存中有如下三个连续的字节数据:

[0110,0001] [0110,0010] [0110,0011]

将它们按6个bit位进行分组后的形式如下:

[0110,00] [01,0110,] [0010,01] [10,0011]

分组后得到了四组数据,每组数据对应的十进制数值分别为24、22、9、35,它们分别对应Y、W、J、j这四个字符,所以,对[0110,0001] [0110,0010] [0110,0011]这三个字节的数据进行BASE64编码后的结果是“YWJj”。

BASE64编码要求把3个8位字节(即24个bit)的数据转化为4个6位字节(也是24个bit)的数据,如果原来的8位字节数据的字节个数不能被3整除,其余数只能是1或2,那么如何对余下的1个或2个8位字节数据进行处理呢?对于这种情况,仍然按6个bit位对剩余的字节进行分组,在最后不够6个bit位的内容后面添加几个为0的bit位来凑成6个bit位,例如,如果最后剩下的一个8位字节的内容如下:

[0110,0001]

对它进行分组后的结果如下:

[0110,00] [01,0000]

其中用黑斜体标识的0为填充的bit位,所以,最后剩下的这个字节的BASE64编码结果为“YQ”。BASE64编码还有规定,如果编码后的整个结果文本的字符个数不是4的整数倍,那么需要在最后填充“=”字符来凑成4的倍数,所以,在最后这个字节编码的结果后面还要添加两个“=”字符,即“YQ==”。显然,如果最后剩下两个8位字节的内容,它可以被编码成三个字符,最后还需要添加一个“=”字符。对一大段数据进行BASE64编码时,可以在编码结果中的适当位置加入回车换行,MIME规范建议BASE64编码结果中的每行最多76个字符。

—  Quoted-printable

Quoted-printable也是一种将二进制数据转换成可打印的ASCII字符的编码方式,它对ASCII字符不进行转换,只对非ASCII字符的数据进行编码转化。每个非ASCII字符的字节数据,都被转换成一个"="号后跟这个字节的十六进制数据,例如,“ab中国”的Quoted-printable编码结果为“ab=d6=d0=b9= fa”。显然,由于"="号在Quoted-printable编码中具有的特殊意义,所以,原始数据中的"="号字符也需要进行编码转换,用“=3d”表示。

对一大段数据进行Quoted-printable编码时,可以在编码结果中的适当位置加入回车换行,在回车换行前需要额外再加入一个“=”字符,以表示后面的换行是因编码而造成的软回车,而非原始数据中原有的回车换行。例如,对于下面一段Quoted-printable编码后的数据:

=D5=E2=CA=C7=CD=A8=D0=C5=B5=C4=B3=CC=D0=

=F2, =C7=EB=D6=B8=BD=CC!

在第一行末尾的“=”字符和换行,都是由于编码后生成的。

posted @ 2008-07-31 10:52 春天花会开 阅读(2518) | 评论 (0)编辑 收藏

几个MIME相关有用资源

记录几个MIME相关有用资源,以备后用:
http://www.mhonarc.org/~ehood/MIME/
http://www.cppblog.com/javenstudio
《javamail开发详解》试读
MIME面面观

posted @ 2008-07-31 09:20 春天花会开 阅读(133) | 评论 (0)编辑 收藏

2007年3月15日 #

微软副总裁张亚勤:用人

  Q:在你的用人之道里,你比较看重的是什么?

  A:诚信永远是第一位的,然后是智慧、热情和团队精神。我认为人的素质有先天和后天两个方面。我把前者定义为IQ’,IQ’由原始智商加冒险精神组成。一个人有没有冒险精神,敢不敢赌一把,敢不敢承担风险,这些都是先天的成分,不容易改变。先天的素质有点像操作系统,预装了就很难动了。而后天的素质我定义为EQ’,这是可以改变的,相当于应用软件和用户界面。

  过去由于工作关系,我跟全球最顶尖的500个公司的CEO有不同程度接触,发现他们很不一样,有的人热情、奔放,有的人内敛,甚至有点害羞,有的人口才很好,有的人结巴。但这些领袖有一些共性,第一是简化抽象问题的能力;第二是信心,这是后天培养的,如果你看这些人的眼睛,都透着自信,尽管他们可能说话很温和,声调不高,语言不一定优美,但是他们总是有信念的;第三是判断力,这完全可以通过后天学习培养,好的领导者很重要的能力在于判断,特别是没有充分的数据情况下,可以及时作出决定的能力。其实在管理一个大公司时,缺的不是聪明的人,重要的是用什么样的人;缺的不是想法,有的时候有太多的想法,重要的是选择哪个想法,什么时候做判断,做什么样的判断。另外一点是心态很重要,所有的优秀领袖都很坚韧,他们每个人都不是一帆风顺的,既有辉煌也有失落,但他们在失落时也可以保持平和的心态,与外界表现出一种和谐。这在谈判、研发时都很重要。

  Q:你不能容忍的品质是什么?

  A:有三种人我不能容忍。一种是双面人,其中包括两面三刀的和老好人。后者为了不得罪人,见不同人会说不同话,其实这样的人没有坏的动机,但是会弱化大家的判断力,而且大家对后者没有防备。

  第二种是负面人,对任何事情都不同意,其实这样的人自己也不一定有观点。人们可以有不同意的观点,但一定要有建设性,以正面的方式提出来。这种人是具有传染性的,一定要清除。

  第三种是玩世不恭的人,他们对任何事情无所谓。

  这三种人能给机会可以尽量给机会,否则一定要清除。领导最重要的是找到对的人,但同样重要的是,能够清除不合适的人。


张亚勤个人档案
  1966年出生于山西太原,12岁考入中国科技大学少年班,23岁获得美国乔治·华盛顿大学电气工程博士学位。

  1999年回国参与创办微软亚洲研究院;2004年赴微软总部负责移动通信及嵌入式系统设备部门的软件研发;2006年再次回国出任微软中国研发集团总裁。

  加盟微软之前,先后在美国 Sarnoff 公司任多媒体实验室总监,以及美国GTE 实验室任高级研究员。

posted @ 2007-03-15 11:49 春天花会开 阅读(331) | 评论 (0)编辑 收藏

2007年1月25日 #

汉字简介

汉字是汉语书写的最基本单元,其使用最晚始于商代,历经甲骨文、大篆、小篆、隶书、楷书(草书、行书)诸般书体变化。秦始皇统一中国,李斯整理小篆,“书同文”的历史从此开始。尽管汉语方言发音差异很大,但是书写系统的统一减少了方言差异造成的交流障碍。

  东汉许慎在《说文解字》中将汉字构造规律概括为“六书”:象形、指事、会意、形声、转注、假借。其中,象形、指事、会意、形声四项为造字原理,是“造字法”;而转注、假借则为用字规律,是“用字法”。

  三千余年来,汉字的书写方式变化不大,使得后人得以阅读古文而不生窒碍。但近代西方文明进入东亚之后,整个汉字文化圈的各个国家纷纷掀起了学习西方的思潮,其中,放弃使用汉字是这场运动的一个重要方面。这些运动的立论以为:跟西方拼音文字相比,汉字是繁琐笨拙的。许多使用汉字国家即进行了不同程度的汉字简化,甚至还有完全拼音化的尝试。日文假名的拉丁转写方案以及汉语多种拼音方案的出现都是基于这种思想。中国大陆将汉字笔划参考行书草书加以省简,于1956年1月28日审订通过《简化字总表》,在中国及新加坡使用至今。台湾则一直使用繁体中文。

  目前在使用汉语的地区,大都使用两种规范汉字,分别是繁体中文(繁体字)和简体中文(简体字)。


  汉字,是记录汉语的文字系统,并仍然或曾经在日语和朝鲜语、越南语中使用。汉字是世界上最古老的文字之一,拥有4500年以上的历史。狭义地说,它是汉族的文字;广义地言,它是汉字文化圈共同的文字。

  汉字是承载文化的重要工具,目前留有大量用汉字书写的典籍。不同的方言都使用汉字作为共同书写体系,因而汉字在历史上对中华文明的传播起到了重要作用,并成为东南亚文化圈形成的内在纽带。在汉字发展过程中,留下了大量诗词、对联等文化,并形成了独特的汉字书法艺术。

  一个汉字一般具有多种含义,也具有很强的组词能力,且很多汉字可独立成词。这导致了汉字极高的“使用效率”,2000左右常用字即可覆盖98%以上的书面表达方式。加之汉字表意文字的特性,汉字的阅读效率很高。汉字具备比字母文字更高的信息密度,因此,平均起来,同样内容的中文表达比其他任何字母语言的文字都短。

  目前的汉字体系分为繁体字和简体字,前者用于台湾、香港、澳门和北美的华人圈中,后者用于中国大陆和新加坡以及东南亚的华人社区。通常说来,两种汉字书写系统虽然有差异,常用汉字的个体差异不到25%。

  由于汉字书写复杂,“汉字落后论”的说法存在了很长时间,认为汉字是教育及信息化瓶颈,并有“汉字拉丁化”甚至废除汉字的推动行为。现在一般认为汉字也有突出优点,初始学习难度虽大,但掌握常用字后不存在类似海量英文单词的继续学习问题,且其表意特性也能充分调动人脑的学习能力。在计算机输入问题基本解决后,“汉字落后论”及“汉字拉丁化”已实际上逐渐被大多数人抛弃。

  目前汉字系统已经基本稳定,但汉字的规范化、生僻字的自然消亡仍在继续进行。

  关于汉字编码

  为进行信息交换,各汉字使用地区都制订了一系列汉字字符集标准。

  ① GB2313字符集,收入汉字6763个,符号715个,总计7478个字符,这是大陆普遍使用的简体字符集。楷体-GB2313、仿宋-GB2313、华文行楷等市面上绝大多数字体支持显示这个字符集,亦是大多数输入法所采用的字符集。市面上绝大多数所谓的繁体字体,其实采用的是GB-2313字符集简体字的编码,用字体显示为繁体字,而不是直接用GBK字符集中繁体字的编码,错误百出。

  ② BIG-5字符集,收入13060个繁体汉字,808个符号,总计13868个字符,目前普遍使用于台湾、香港等地区。台湾教育部标准宋体楷体等港台大多数字体支持这个字符集的显示。

  ③ GBK字符集,又称大字符集(GB=GuóBiāo国标,K=扩展),包含以上两种字符集汉字,收入21003个汉字,882个符号,共计21885个字符,包括了中日韩(CJK)统一汉字20902个、扩展A集(CJK Ext-A) 中的汉字52个。Windows 95\98简体中文版就带有这个GBK.txt文件。宋体、隶书、黑体、幼圆、华文中宋、华文细黑、华文楷体、标楷体(DFKai-SB)、Arial Unicode MS、MingLiU、PMingLiU等字体支持显示这个字符集。微软拼音输入法2003、全拼、紫光拼音等输入法,能够录入如镕镕炁夬喆嚞姤赟赟龑昳堃慜靕臹等GBK简繁体汉字。

  BIG-5 (繁体中文)与GB-2313 (简体中文),编码不相兼容,字符在不同的操作系统中便产生乱码。文本文字的简体与繁体(文字及编码)之间的转换,可用BabelPad、TextPro或Convertz之类的转码软件来解决。若是程序,Windows XP操作系统,可用Microsoft AppLocale Utility 1.0解决;Windows 2000的操作系统,大概只有用:中文之星、四通利方、南极星、金山快译之类的转码软件方能解决了。

  ④ GB18030字符集,包含GBK字符集、CJK Ext-A 全部6582个汉字,共计27533个汉字。宋体-18030、方正楷体(FZKai-Z03)、书同文楷体(MS Song)宋体(ht_cjk+)、香港华康标准宋体(DFSongStd)、华康香港标准楷体、CERG Chinese Font、韩国New Gulim,以及微软Windows Vista操作系统提供的宋黑楷仿宋等字体亦支持这个字符集的显示。Windows 98支持这个字符集,以下的字符集则不支持。手写输入法逍遥笔4.0版支持GB18030字符集及方正超大字符集汉字的录入。

  ⑤ 方正超大字符集,包含GB18030字符集、CJK Ext-B中的36862个汉字,共计64395个汉字。宋体-方正超大字符集支持这个字符集的显示。Microsoft Office XP或2003简体中文版就自带有这个字体。Windows 2000的操作系统需安装超大字符集支持包“Surrogate更新”。

  ⑥ ISO/IEC 10646 / Unicode字符集,这是全球可以共享的编码字符集,两者相互兼融,涵盖了世界上主要语文的字符,其中包括简繁体汉字,计有:CJK统一汉字20902个,CJK Ext-A 6582个,Ext-B 42711个,共计70195个汉字。SimSun-ExtB(宋体)、MingLiU-ExtB(细明体)能显示全部Ext-B汉字。至今尚无单独一款字体能够显示全部70195个汉字,但可用海峰五笔、新概念五笔、仓颉输入法世纪版、新版的微软新注音、仓颉输入法 6.0 版(单码功能)等输入法录入。Ext-C还有2万多个汉字。详情请参阅香港中文大学网站、马来西亚仓颉之友网站、福建陈清钰个人网站。

  ⑦ 汉字构形数据库2.3版,内含楷书字形60082个、小篆11100个、楚系简帛文字2627个、金文3459个、甲骨文177个、异体字12768组。可以安装该程序,亦可以解压后使用其中的字体文件,对于整理某些古代文献十分有用。

  如果超出了输入法所支持的字符集,就不能录入计算机。如果没有相应字体的支持,则显示为黑框、方框或空白。如果操作系统或应用软件不支持该字符集,则显示为问号(一个或两个)。在网页上亦存在同样的情况。

  关于Unicode

  由于各国国家标准字集所收的汉字字数、常用字的差异,虽然象中国两岸GB/BIG5字集常用字基本类似,转换后阅读并不成问题,但是这种编码转换的混乱关系,对文字交流始终是一种障碍。因此相关国家的标准化组织和文字工作者经过共同努力,终于在93年完成了包含中日韩(CJK)汉字的Unicode 汉字标准ISO 10646.1。 Unicode是完全双字节表示的多国文字编码体系,编码空间0x0000-0xFFFF。 ISO 10646.1汉字标准使用编码0x4E00-9FA5,共包含20902个汉字。其中:大陆(S)提出的汉字17124个,台湾(T)提出的汉字17258个; S与T的并集,即中国(C)提出的汉字为20158个。日本(J)提出的汉字为12157个,中国未提出的690个(Ja); 韩国(K)提出的汉字为7477个,其中中国未提出的90个(Ka); Ja与Ka并集共744字。 支持Unicode编码的相关电脑系统软件,如Unix, Win95已有推出,但是由于Unicode的ASCII码是用双字节编码(即一般电脑系统中的单字节ASCII码前加 0x00),同时其汉字编码与各国的现有编码也不兼容,造成现有的软件和数据不能直接使用,所以目前完全使用Unicode软件系统的用户并不多,大多数只将它此作为一个国际语言编码标准来使用。

posted @ 2007-01-25 19:59 春天花会开 阅读(293) | 评论 (0)编辑 收藏

2006年10月17日 #

[原创]javascript封装的Tab类-附源码

Web UI中常常用到Tab,每次写一堆HTML+css有点烦了,于是花了点时间整理了这个class,留备后用。
为了方便我引入了prototype 1.4,省掉一串键盘敲击。
类比:www.live.com的Tab page
用法:
//首先载入: 'tab.js','prototype.js' and 'tab.css' in HTML page
//   mytab1=new Tab('tab1',top,left,width,height);//创建新Tab
//   mytab1.addItem(name,contentid,type);//添加TabItem
//   mytab1.delItem(name);//删除TabItem
//   当然一般情况下操作鼠标即可完成添加/删去工作.
//   点击TabItem时动态调用 <li>标签rev属性指定的方法(要不要ajax就随你喜欢了)
例子:

o_LuTab.png
<html>
<head>
<script src='prototype.js'></script>
<script src='tab.js'></script>
<link
rel=stylesheet type="text/css" href='tab.css'/>
</head>
<body>
<script><!--
//Test case
tab1=new Tab("tab1",100,10,600,300);
tab2=new Tab("tab2",180,60,600,300);
tab3=new Tab("tab3",260,110,600,300);

tab1.addItem('hello','id','CONTENT');
tab1.delItem('t2');
tab1.addItem();tab1.addItem();

tab2.addItem('hi','id','CONTENT');
tab2.addItem();tab2.addItem();

tab1.display();
tab2.display();
tab3.display();

--></script>
</body>
</html>

下载Tab.rar

posted @ 2006-10-17 09:16 春天花会开 阅读(2160) | 评论 (3)编辑 收藏

2006年8月18日 #

javascript vml 封装的3D饼图

原型是在网上找的,对vml我不是很熟悉,基本上是一样画葫芦。
做的最主要的事情是把vml用javascript封装成Pie3D类,方便重用。
Snap1.png

Pie3D.js代码太长,我已打包,需要的话自行下载。javascript vml 封装的3D饼图

<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office"> 
<head>        
<!-- 样式表 -->
<STYLE>
v\:* {Behavior: url(#default#VML) }
o\:* {behavior: url(#default#VML) }
body{font-family:arial}
</STYLE>
<title>3D Pie</title>
<script src=Pie3D.js ></script>
</head>
<body>
<div id='pieChart'></div>
<script>
xxColor=new Array("#ccc","#b5cc88","#6B8E23","#3CB371","#f59d56","yellow","#d8d8d8","#708090","#4682B4","red","#ffc20e");
//参数('容器div的id',宽度,高度,'图表标题')
var
 pie=new Pie3D('pieChart',320,192,'TEST 3D PIE');
//测试数据,数据格式("项目名称",值,"颜色")
//此处可结合Ajax,取得数据后动态更新

for(var i=0;i<10;i++){
dcake=new Array("cake"+i,Math.random()*10,xxColor[i]);
pie.Cakes[i]=dcake;
//赋值
}

pie.draw();//画图
</script>
</body></html>

posted @ 2006-08-18 15:40 春天花会开 阅读(5130) | 评论 (11)编辑 收藏

2006年8月15日 #

Virtual Fab(虚拟工厂)

posted @ 2006-08-15 12:07 春天花会开 阅读(511) | 评论 (0)编辑 收藏

2006年7月19日 #

LuEmail 客户端+服务器代码全部开放

因为时间的原因我无法再花大量的精力在LuEmail的后续开发上,所以决定把客户端+服务器代码全部开放,希望有兴趣的朋友可以帮忙继续下去。当然,也希望这个project的一些片段能为初学者带来启发。
我没有把js和css分出来,总共1500行左右,放在一起比较方便查找。
总体来说第一部分css(格式),第二部分js(功能),第三部分html(页面)。


补充:7/20 8:15 补充进用到的所有图表+自动完成js+邮件编辑器js
LuEmail 客户端代码
LuEmail 服务器代码

posted @ 2006-07-19 17:39 春天花会开 阅读(1261) | 评论 (7)编辑 收藏

2006年7月7日 #

javascript 滑动框架的制作

function  drag(o,r){

//o.firstChild.onmousedown=function(){return false;};

o.onmousedown=function(a){

var  d=document;

if (!a)a=window.event;

o.style.backgroundColor="#0066ff"

var  x=a.layerX?a.layerX:a.offsetX,y=a.layerY?a.layerY:a.offsetY;

//-------------for resize

var  leftdiv=document.getElementById("leftregion");

var  leftdivwidth=parseInt(leftdiv.style.width);

//leftdiv.innerHTML+="width:"+leftdivwidth+"<br>"

var  rightdiv=document.getElementById("rightregion");

var  rightdivwidth=parseInt(rightdiv.style.width);

var  xx=a.pageX?a.pageX:a.clientX,yy=a.pageY?a.lpageY:a.clientY;

var  oleft=parseInt(o.style.left)//xx-x;

var  rightdivleft=parseInt(rightdiv.style.left);

//leftdiv.innerHTML+=o.style.width;//only for tracing

if (o.setCapture)

o.setCapture();

else  if(window.captureEvents)

window.captureEvents(Event.MOUSEMOVE|Event.MOUSEUP);

d.onmousemove=function(a){

if (!a)a=window.event;

if (!a.pageX)a.pageX=a.clientX;

if (!a.pageY)a.pageY=a.clientY;

//clientX: distance between explorer and mouse point

var  tx=a.pageX-x,ty=a.pageY-y;

//------------for resize

var  txx=a.pageX-xx,tyy=a.pageY-yy

o.style.left=tx<r[0]?r[0]:tx>r[1]?r[1]:tx;

//o.style.top=ty<r[2]?r[2]:ty>r[3]?r[3]:ty;

move_x=parseInt(o.style.left)-oleft;

//move_y=otop-o.style.top

//leftdiv.innerHTML+="width:"+leftdiv.style.width+" move:"+move_x+"<br>"

//rightdiv.innerHTML+="o left:"+o.style.left+" move:"+move_x+"<br>"

leftdiv.style.width=(leftdivwidth+move_x)+"px"

rightdiv.style.width=(rightdivwidth-move_x)+"px"

rightdiv.style.left=(rightdivleft+move_x)+"px"

} ;

d.onmouseup=function(){

o.style.backgroundColor="#FFFFFF"

if (o.releaseCapture)

o.releaseCapture();

else  if(window.captureEvents)

window.captureEvents(Event.MOUSEMOVE|Event.MOUSEUP);

d.onmousemove=null;

d.onmouseup=null;

} ;

} ;

}

posted @ 2006-07-07 21:20 春天花会开 阅读(818) | 评论 (0)编辑 收藏

Servlet获取Ajax POST数据乱码的一种解法

1. 对中文参数编码encodeURI(chinesePara);
  poststr = "username="+encodeURI("中文");

2.服务器端获取参数后解码

String username = new String(request.getParameter("username").getBytes("ISO-8859-1"),"UTF8");  

  -----------------------------------------------------------

  http_request.open("POST", url, true);
  http_request.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
  http_request.send(poststr);

---------------------------------------------------------------

posted @ 2006-07-07 21:17 春天花会开 阅读(2614) | 评论 (1)编辑 收藏

LuEmail主界面构架

文字我就不多说了,大家看图~

ReadStructure.PNG

WriteStructure.PNG

posted @ 2006-07-07 09:12 春天花会开 阅读(817) | 评论 (6)编辑 收藏

LuEmail 我想做的更好

基本上可以work了,现在暂时没有空间~

基于Web的邮件客户端,后端邮件服务器暂时只测试了Open WebMail

HTML+javascript+Ajax+Servlet+Javamail+Tomcat

页面构架上采用CSS布局。

  • 标记功能可以让您方便为每一封邮件添加提醒
  • 双击邮件阅读区域即可切换视图,让您立刻拥有开阔的视野
  • 通过阅读窗格使您无需离开收件箱,即可快速查看邮件内容
  • 单击右键,轻松回复,删除及转发
  • 支持直接插入本地图片,无须先手动上传再Copy Url
  • 实时搜索,输入不超过3个字母即可找到您要的邮件(主题、收件人)
  • 自动补全,写信时不必记忆长窜的Email地址Main.PNG
  • posted @ 2006-07-07 08:27 春天花会开 阅读(973) | 评论 (10)编辑 收藏

    2006年7月2日 #

    javamail读取完整的邮件

    Javamail API虽然功能封装的比较完整,但是要写一个能正确显示复杂邮件的程序还有很多逻辑和细节要处理。下面是我最近做一个webmail时整理的Servlet,基本上可以正确的读取text,HTML,HTML中显示图片及附件。在本servlet中也简单处理了常见的中文问题,包括主题、附件、HTML图片中文、email Address中文。总体感觉有两个难点:1、附件和网页图片的抓取,需要定位数节点nodeid,光用partid是不行的;2、中文分两种情况Base64和客户端服务器端编码不一致。本程序中实现了3种displayPart()的方法,具体情况不同结合使用效率更高。本程序还有一个未处理的地方就是我在做nodeid的时候最多算10个。当然还有其他问题欢迎指正,来出是为了给后来的初学者作个参考例子,少走弯路。
      1 import  java.io.IOException;
      2 import  java.io.InputStream;
      3 import  java.io.UnsupportedEncodingException;
      4 import  java.util.HashMap;
      5 import  javax.mail.Folder;
      6 import  javax.mail.Message;
      7 import  javax.mail.MessagingException;
      8 import  javax.mail.Multipart;
      9 import  javax.mail.Part;
     10 import  javax.mail.Store;
     11 import  javax.mail.internet.InternetAddress;
     12 import  javax.mail.internet.MimeUtility;
     13 import  javax.servlet.ServletException;
     14 import  javax.servlet.ServletOutputStream;
     15 import  javax.servlet.http.HttpServletRequest;
     16 import  javax.servlet.http.HttpServletResponse;
     17 import  javax.servlet.http.HttpSession;
     18 import  chunwei.mail.Login;
     19 import  chunwei.mail.MailUserData;
     20 /**
     21 * Servlet implementation class for Servlet: MailServlet
     22 * Author: luchunwei  Email: luchunwei@gmail.com
     23 */
     24 public  class MailNode extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
     25 private  static final long serialVersionUID = 1L;
     26 protected  void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     27 nodeid="";
     28 node="0";
     29 currentnodeid=0;
     30 url=request.getRequestURL().toString();
     31 HttpSession ses=request.getSession();
     32 MailUserData mud=(MailUserData)ses.getAttribute("mud");
     33 ServletOutputStream out=response.getOutputStream();
     34 response.setContentType("text/html;charset=GB2312");
     35 int  msgid=-1,partid=-1;//msgdi:邮件编号;partid:MultiPart Message中part的编号。
     36 String  partname=null//图片或附件的文件名
     37 String  nodepara=null;//节点编号,如1-2-1-0, 他以便层层剥入
     38 if (request.getParameter("msgid")!=null)
     39 msgid=Integer.parseInt(request.getParameter("msgid"));
     40 msgidStr="msgid="+msgid;
     41 if (request.getParameter("partid")!=null)
     42 partid=Integer.parseInt(request.getParameter("partid"));
     43 if (request.getParameter("partname")!=null)
     44 partname=new String(request.getParameter("partname").getBytes("ISO-8859-1"),"GB2312");
     45 if (request.getParameter("node")!=null)
     46 nodepara=request.getParameter("node");
     47 System.out.println(nodepara);
     48 //System.out.println(msgid+":"+partid+":"+partname);
     49 if (partname!=null){
     50 //displayImages
     51 try  {
     52 displayPart(partname,response,out);
     53 }  catch (MessagingException e) {
     54 e.printStackTrace();
     55 }  catch (IOException e) {
     56 e.printStackTrace();
     57 }
     58 return;
     59 }
     60 //--------------------------
     61 if (mud==null){
     62 Login login=new Login("imap","mail.server.com",-1,"user","password");
     63 login.login();
     64 if (login.getResult()==1){
     65 HttpSession session = request.getSession();
     66 session.setMaxInactiveInterval(3600);
     67 session.setAttribute("mud",login.getMud());
     68 }
     69 mud=(MailUserData)ses.getAttribute("mud");
     70 }
     71 //---------------------------
     72 if (mud==null){
     73 out.print("<error>Login First(No Session)</error>");
     74 } else{
     75 //Folder folder=mud.getFolder();
     76 try  {
     77 //------------------------
     78 Store store=mud.getStore();
     79 Folder  folder=store.getFolder("INBOX");
     80 folder.open(Folder.READ_ONLY);
     81 //------------------------
     82 Message m=folder.getMessage(msgid);
     83 //if(partid==-1){
     84 if (nodepara==null){
     85 //if(!imgs.isEmpty())imgs.clear();
     86 messageHtml="";
     87 attachment="";
     88 recipients=getAllgetRecipients(m);
     89 out.print(displayMessage(request,m,partid));
     90 } else{
     91 displayPart(m,nodepara,response,out);
     92 }
     93 }  catch (MessagingException e) {
     94 e.printStackTrace();
     95 }  catch (IOException e) {
     96 e.printStackTrace();
     97 }  catch (Exception e) {
     98 e.printStackTrace();
     99 }
    100 }
    101 }       
    102 protected  void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    103 doGet(request,response);
    104 }  
    105 String  stdUrl="";
    106 String  url="";
    107 String  msgidStr="";
    108 String  messageHtml="";
    109 String  attachment="";
    110 String  recipients="";
    111 String  nodeid="";
    112 int  currentnodeid=0;
    113 String  node="";
    114 HashMap<String,Part> imgs=new HashMap<String,Part>();
    115 public  String displayMessage(HttpServletRequest request,Part p,int partid) throws Exception{
    116 //System.out.println("Type:"+p.getContentType());
    117 if (currentnodeid==1&&!node.endsWith("0")){
    118 nodeid=nodeid.substring(0,(nodeid.length()-2));
    119 }
    120 node=nodeid+currentnodeid;
    121 System.out.println(node);
    122 if (p.isMimeType("multipart/*")){
    123 nodeid+=currentnodeid+"-";
    124 Multipart mp=(Multipart) p.getContent();
    125 int  cnt=mp.getCount();
    126 String  mpct=mp.getContentType().toLowerCase();
    127 for (int i=0;
    128 i<cnt;
    129 i++){
    130 if (mpct.startsWith("multipart/alternative")&&mp.getBodyPart(i).getContentType().toLowerCase().startsWith("text/plain"))continue;
    131 currentnodeid=i;
    132 displayMessage(request,mp.getBodyPart(i),i);
    133 }
    134 }
    135 if (p.isMimeType("text/plain")||p.isMimeType("text/html")){
    136 if (messageHtml=="") {
    137 messageHtml=(String)p.getContent();
    138 //System.out.println(messageHtml);
    139 }  else {
    140 messageHtml=messageHtml+"<HR/>"+(String)p.getContent();
    141 //System.out.println(messageHtml);
    142 }
    143 }  else if (p.isMimeType("message/rfc822")) {
    144 //Nested Message
    145 //displayMessage(request,(Part)p.getContent(),partid);
    146 else{
    147 if (node.length()>2)    node=node.substring(2);
    148 System.out.println(node);
    149 String  disposition=p.getDisposition();
    150 //System.out.println("disposition:"+disposition);
    151 if (disposition!=null&&disposition.equalsIgnoreCase(Part.ATTACHMENT)){
    152 String  filename=getFileName(p);
    153 //imgs.put(filename,p);
    154 //attachment全部放入内存,会造成内存膨胀;若及时清空又造成Back回来的页面访问不到Attachment
    155 //attachment+=","+"<a href='"+url+"/"+filename+"?"+msgidStr+"&partid="+partid+"'>"+filename+"</a>";
    156 attachment+=","+"<a href='"+url+"/"+filename+"?"+msgidStr+"&node="+node+"'>"+filename+"</a>";
    157 //attachment+=","+"<a href='"+url+"/"+filename+"?"+"&partname="+getFileName(p)+"'>"+filename+"</a>";
    158 //System.out.println(attachment);
    159 else{
    160 //if(disposition!=null&&disposition.equalsIgnoreCase(Part.INLINE)){
    161 if (getCid(p)!=null)    {
    162 //System.out.println("Enter Replace");
    163 imgs.put(getFileName(p),p);
    164 //String uri=url+"?"+msgidStr+"&partid="+partid;
    165 String  uri=url+"?"+msgidStr+"&node="+node;
    166 //String uri=url+"?"+"&partname="+getFileName(p);
    167 String  t=messageHtml.substring(messageHtml.indexOf(getCid(p))-1);
    168 if (!(t.startsWith("\"")||t.startsWith("\'"))){
    169 uri="'"+uri+"'";
    170 }
    171 messageHtml=messageHtml.replace(getCid(p),uri);
    172 //System.out.println("cid:"+getCid(p));     
    173 //System.out.println(uri);
    174 }
    175 }
    176 }
    177 return  messageHtml+"attachhncwx="+attachment+recipients;
    178 }
    179 public  void displayPart(Message m,String node,HttpServletResponse response,ServletOutputStream out) 
    180 throws MessagingException, IOException{
    181 Part part = getPart(m,node);
    182 String  sct = part.getContentType();
    183 response.setContentType(sct);
    184 outPut(part,out);
    185 }
    186 private  Part getPart(Part m, String nodes) throws NumberFormatException, MessagingException, IOException {
    187 if (node==null)return m;
    188 String  node=nodes.substring(0,1);
    189 System.out.println(nodes+" : "+node);
    190 int  nid=Integer.parseInt(node);
    191 if (m.getContent()==null)System.out.print("no content");
    192 Part p=((Multipart)m.getContent()).getBodyPart(nid);
    193 if (nodes.length()>2)nodes=nodes.substring(2);
    194 else  {
    195 if (nodes.length()==1)nodes="";
    196 }
    197 if (nodes.length()>0)p=getPart(p,nodes);
    198 return  p;
    199 }
    200 public  void displayPart(String partname,HttpServletResponse response,    ServletOutputStream out) throws MessagingException, IOException{
    201 //System.out.println(imgs.keySet()+":"+partname);
    202 Part part=imgs.get(partname);
    203 String  ct=part.getContentType();
    204 if (ct!=null)        response.setContentType(ct);
    205 //=====Start push Stream into out
    206 InputStream in=part.getInputStream();
    207 ByteArrayOutputStream bos=new ByteArrayOutputStream();
    208 byte [] buffer=new byte[8192];
    209 int  count=0;
    210 while ((count=in.read(buffer))>=0) bos.write(buffer,0,count);
    211 in .close();
    212 try{
    213 out.write(bos.toByteArray());
    214 out.flush();
    215 } catch(Exception e){
    216 }
    217 out.close();
    218 //=====End
    219 }
    220 public  void displayPart(Message m,int partid,HttpServletResponse response,        ServletOutputStream out) throws MessagingException, IOException{
    221 Multipart mp = (Multipart)m.getContent();
    222 Part part = mp.getBodyPart(partid);
    223 String  sct = part.getContentType();
    224 // ContentType ct = new ContentType(sct);
    225 response.setContentType(sct);
    226 if  (sct == null) {
    227 out.println("invalid part");
    228 return;
    229 }
    230 //=====Start push Stream into out
    231 InputStream in=part.getInputStream();
    232 ByteArrayOutputStream bos=new ByteArrayOutputStream();
    233 byte [] buffer=new byte[8192];
    234 int  count=0;
    235 while ((count=in.read(buffer))>=0) bos.write(buffer,0,count);
    236 in .close();
    237 try{
    238 out.write(bos.toByteArray());
    239 out.flush();
    240 } catch(Exception e){
    241 }
    242 out.close();
    243 //=====End
    244 }
    245 private  String getFileName(Part p) throws MessagingException, UnsupportedEncodingException{
    246 //System.out.println("filename:");
    247 String  filename=p.getFileName();
    248 if (filename==null)return null;
    249 filename=new String(filename.getBytes("ISO-8859-1"),"GB2312");
    250 int  indexStart=filename.toUpperCase().indexOf("=?GB");
    251 if (indexStart>-1){
    252 filename=filename.substring(0,indexStart)+MimeUtility.decodeText(filename.substring(indexStart));
    253 }
    254 return  filename;
    255 }
    256 private  String getCid(Part p) throws MessagingException{
    257 String  cidraw=null,cid=null;
    258     
    259 String [] headers=p.getHeader("Content-id");
    260 if (headers!=null && headers.length>0) {
    261 cidraw=headers[0];
    262 } else{
    263 return  null;
    264 }
    265 if (cidraw.startsWith("<")&&cidraw.endsWith(">")) {
    266 cid="cid:"+cidraw.substring(1,cidraw.length()-1);
    267 }  else {
    268 cid="cid:"+cidraw;
    269 }
    270 return  cid;
    271 }
    272 /**
    273 * 获得邮件的收件人,抄送,和密送的地址和姓名,根据所传递的参数的不同 "to"----收件人 "cc"---抄送人地址 "bcc"---密送人地址
    274 @throws Exception 
    275 */
    276 private  String getAllgetRecipients(Message m) throws Exception{
    277 return  "mailaddrTo="    +getRecipients(m,"TO")
    278 +"mailaddrCc="+getRecipients(m,"CC")
    279 +"mailaddrBcc="+getRecipients(m,"BCC");
    280 }
    281 private  String getRecipients(Message m,String type) throws Exception {
    282 StringBuffer mailaddr = new StringBuffer("");
    283 String  addtype = type.toUpperCase();
    284 InternetAddress[] address = null;
    285 if  (addtype.equals("TO")) {
    286 address = (InternetAddress[]) m.getRecipients(Message.RecipientType.TO);
    287 }  else if (addtype.equals("CC")) {
    288 address = (InternetAddress[]) m.getRecipients(Message.RecipientType.CC);
    289 }  else {
    290 address = (InternetAddress[]) m.getRecipients(Message.RecipientType.BCC);
    291 }
    292 if  (address != null) {
    293 for  (int i = 0;
    294 i < address.length;
    295 i++) {
    296 String  email = address[i].getAddress();
    297 if  (email == null)
    298 email = "";
    299 else  {
    300 email = MimeUtility.decodeText(email);
    301 }
    302 String  personal = address[i].getPersonal();
    303 if  (personal == null)
    304 personal = "";
    305 else  {
    306 personal = MimeUtility.decodeText(personal);
    307 }
    308 mailaddr.append("\""+personal+"\" ");
    309 mailaddr.append("<");
    310 mailaddr.append(email);
    311 mailaddr.append(">");
    312 mailaddr.append(",");
    313 }
    314 }
    315 if (mailaddr.length()>0)mailaddr.deleteCharAt(mailaddr.length()-1);
    316 return  mailaddr.toString();
    317 }
    318 private  void outPut(Part part,ServletOutputStream out) throws IOException, MessagingException{
    319 //=====Start push Stream into out
    320 InputStream in=part.getInputStream();
    321 ByteArrayOutputStream bos=new ByteArrayOutputStream();
    322 byte [] buffer=new byte[8192];
    323 int  count=0;
    324 while ((count=in.read(buffer))>=0) bos.write(buffer,0,count);
    325 in .close();
    326 try{
    327 out.write(bos.toByteArray());
    328 out.flush();
    329 } catch(Exception e){
    330 }
    331 out.close();
    332 //=====End
    333 }
    334 }


    posted @ 2006-07-02 08:17 春天花会开 阅读(9195) | 评论 (14)编辑 收藏

    仅列出标题