Chinaunix首页 | 论坛 | 博客
  • 博客访问: 90993307
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993308
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993299
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993310
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993311
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993312
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993313
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993314
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993315
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993316
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993317
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993318
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993319
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993320
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993321
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993322
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993323
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993314
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993325
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993326
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993327
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993328
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993329
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993330
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993331
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993332
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993333
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993334
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993335
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993336
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993337
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993338
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993329
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993340
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993341
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993342
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993343
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993344
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993345
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993346
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993347
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993348
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993349
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993350
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993351
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993352
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993353
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993344
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993355
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993356
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993357
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 3 部分: XML 数据操纵(4)-sdccf-ChinaUnix博客
  • 博客访问: 90993358
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:23:14

通过应用程序存储和检索 XML

developerWorks



XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201437) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201436) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201435) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201434) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201433) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201432) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201431) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201430) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201429) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201428) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201427) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201426) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201425) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201424) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201423) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201422) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201421) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201420) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201419) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201418) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201417) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201416) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201415) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201414) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201413) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201412) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201411) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201410) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201409) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201408) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201407) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201406) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201405) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201404) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201403) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201402) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201401) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201400) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201399) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201398) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201397) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201396) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201395) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201394) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201393) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201392) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201391) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201390) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201389) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201388) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201387) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


XML 编码

在历史上,术语 字符集、字符编码码页 都有类似的意义:一个字符集和一个二进制码集,其中每个码表示一个字符。(码页是来自 IBM 的一个术语,表示一个大型主机或 IBM PC 上的一个字符集。) 官方字符集名称由 Internet Assigned Numbers Authority (IANA) 维护。欲了解更多信息,请参阅 参考资料 小节。

西方一些常见的遗留字符集有 US-ASCII、EBCDIC、码页 437、码页 1252、8859-1、1208 和 Latin-1。这些都是将一个字符编码为一个字节。

  • 码页 437: 在美国的 Microsoft Windows 上,默认码页是 437;IANA 官方编码名称为 ibm-437。 它有一些非英语字符(例如 "ae" 连字、带重音的小写元音、一些希腊字母、法语引号 "<<" 和 ">>" 以及 48 个图形字符(DOS 和基于字符的程序的遗产)。

  • 码页 1252: 在 DB2 的开始菜单组中,在 Command Line Tools 下有两个菜单项: Command Line ProcessorCommand Window。它们都是首先运行一个程序 db2clpcp.exe,该程序将码页从默认的 437 改为(美国的)1252。 码页 1252(Microsoft 也称 "Latin-I")中有 "ae" 连字,大写和小写的重音字符以及欧元符号(十六进制码为 0x80),但是没有希腊字母。

  • 码页 1208: 当执行 CREATE DATABASE USING CODESET UTF-8 时,相应的数据库码页为 1208:

    db2 get db cfg for sample | grep "code"
     Database code page                                      = 1208
     Database code set                                       = UTF-8
     Database country/region code                            = 1
    

  • 字符集 iso-8859-1: 该字符集也称 Latin-1,在英国或西欧的 Web 页面上比较常见。它有 "ae" 连字、大写和小写的重音拉丁字母,但是没有希腊字母,也没有欧元符号。

参考资料中可以找到这些字符集和其它字符集的定义的链接。





回页首


任何遗留编码都是有限制的,因为它只能表示少数语言中的文本。管理多种编码是件头痛的事情,这不仅仅是因为大多数应用程序和数据库只能处理一种编码,还有很多其它原因。Unicode 就是为了解决这个问题而发明的。它是用于表示正在使用的所有语言中的所有字符的字符集,并且留有增长空间。

在 Unicode 中,一个字符集的简单思想被精华为 4 个概念:

  • 字符集 就是可以被编码的所有字符的集合。它没有指定编码。
  • 编码字符集是惟一整数的集合,用于表示字符集中的一些或全部字符,一个数字(或 码点)对应一个字符。也称 character set、charsetcode set。它与码页是同义词。Unicode 码点范围为 0 到 0x10FFFF(大约 110 万)。
  • 起初,Unicode 定义了不到 64,000 字符的字符集,所以可以用 16 位(2 字节)码点指定一个编码字符集。随着更多字母表的加入,字符集超过了 64,000 个字符。 另一个问题是,很多处理 US-ASCII 的计算机系统(尤其是用 C 编写的程序)或其它计算机系统使用一个 null 或零字节(在 C 中为 \0)标记一个字符串的结尾。但是将 Unicode 码点直接编码为 16-位或更大的数字时,会包括一些 null 字节,它们会拆散这些程序。

    所以 Unicode 引入了一个新的概念,即字符编码表(CEF), ,它常常被简称为字符编码(character encoding)编码(encoding)。CEF 是从编码字符集中的码点到一组不同的整数(或 code unit)之间的映射,这些字符实际上被编码为其中的整数。编码单元是用于编码字符的最小单元。一个字符可以用一个或多个编码单元表示,从而允许编码更多的字符。

    所以码点 只是用于引用的,因此可以说 “那个 字符”。Java String、C char[] 或文件中的实际字节可能不同,这取决于字符编码表。有些 Unicode 字符编码表是 UTF-8、UTF-16 和 UTF-32。数字 8、16 和 32 表示编码单元中的位数。

    • DB2 使用 UTF-8 为每个字符使用 1 到 4 个编码单元(即字节)。在规定 UTF-8 数据库中的 [VAR]CHAR 列的长度时,这一点很重要:一个字符可能占 1 到 4 个字节。UTF-8 字符编码表不包含任何 null 字节,这种字节对于 C 比较方便。
    • 在 Java 语言使用的 UTF-16 字符编码表中,最常用的码点低于 64K,UTF-16 字符码等于码点。更高的码点需要两个编码单元。
    • UTF-32 是惟一定长的 UTF,它通过增加空间成本简化一些处理。编码单元总是等于码点。

    由于 Unicode 标准限制遗留码点,使所有 UTF 编码都能表示任何码点,因此 UTF 之间的译码不会造成字符丢失。

    Unicode 码点在文档中通常被写为 U+hhhh ,其中 hhhh 表示 4 个十六进制数字,用于 2 字节的码点;对于 64K 以上的码点,由于需要 4 个字节,因此两次使用该语法。 注意,该语法是在文档中使用的,XML 和编程语言中专门有用于指定 Unicode 文字的语法;欲了解更多信息,请参阅下面的 "编码中的字符" 小节。

  • 字符编码模式(character encoding scheme)指定在表示字符的字节流中的一个编码单元中如何排列字节。UTF-16 和 UTF-32 提供了指定字节顺序的方式,即 big-endian(默认)或 little-endian。对于 UTF-8,一个编码单元就是 1 字节,所以不存在顺序 -- 换句话说,无论计算机的 endian 顺序是什么,编码单元的顺序总是一样的。





回页首


不管用什么来处理字符数据,都必须知道字符集、字符编码表和数据的字符编码模式。

在 XML 之外,文本只有外部编码。外部编码由码页定义,或者由环境中的位置、应用程序、变量类型、函数或方法(例如 Java 方法 String.getBytes(String encoding))中指定的编码来定义。

为了确定数据库创建时所基于的数据库码页,可以运行:

db2 get db cfg for 
database-name
                    

,并查看 "Database code page" 参数的值。

在 Windows 上,编码的有些方面取决于安装的操作系统的版本。通过 Control Panel applet "Regional and Language Options" 可以改变地区和键盘的某些方面。可以打开一个命令窗口,输入命令 CHCP,来看看码页是什么。

在 Linux 和 UNIX 上,活动环境是通过地区设置来确定的,地区设置包括关于语言、地区和编码集的信息。为了确定活动码页,运行:

locale

XML 数据还可以有内部编码。内部编码位于 XML 文档的内部。内部编码有两种:

  • 编码属性
  • Byte Order Mark (BOM)

编码属性 在文档顶部的 XML 声明部分,它指定一种官方 IANA 编码名称:

encoding="UTF-8"
 ?>

BOM 是文件开头部分的一系列特殊的字节,它表明一种 Unicode 编码。为了读取 XML 声明,XML 解析器需要知道或猜测编码。但是它可以准确无误地读取 BOM。



BOM 类型 BOM 值 编码
UTF-8 X'EFBBBF' UTF-8
UTF-16 Big Endian X'FEFF' UTF-16
UTF-16 Little Endian X'FFFE' UTF-16
UTF-32 Big Endian X'0000FEFF' UTF-32
UTF-32 Little Endian X'FFFE0000' UTF-32

如果 XML 文档的实际编码、外部编码和内部编码(BOM 或 XML 声明)不一致,那么该文档就是不可读的。一个例外是外部编码为 Unicode(例如使用 UTF-16 的一个 Java String):任何内部编码都被忽略。当一个不支持 XML 的过程译码(也就是改变实际编码)或者在不支持内部编码的情况下更改文档时,就会发生一个常见的问题。Java 语言、CLI 和嵌入式 SQL 应用程序中对字符串的某些处理可以在不改变内部编码的情况下进行译码。欲了解如何避免这个问题,请参阅下面的"建议"小节。





回页首


在 Windows 中,为了在键盘上输入不同语言的文本,可以在 Windows Control Panel 中 "Regional and Language Options" 下单击 Languages 标签页上的 Details 按钮来改变输入语言和键盘布局。可以添加多种语言和键盘,并且用一个热键在它们之间进行切换。(对不起,这里没有 Unicode "语言" 或键盘 -- 因为它必须非常大才行!)

Windows Notepad 实用程序可以用 "ANSI"(windows-1252 或类似)、"Unicode" (UTF-16 little endian,Intel 和 AMD CPU 的 endian 顺序)、"Unicode big endian"(默认 UTF-16)和 UTF-8 编码保存文件。对于 UTF,Notepad 用一个 BOM(没有 XML 声明)预先考虑文件。

在 Java String 文字(采用 Unicode)中,使用一个转义序列:\udddd ,其中 dddd 表示用于 Unicode 码点的 4 个十六进制数字。

在 XML 和 HTML 中,可以为码点使用一个 XML 数字引用(或 字符引用):&#n ,其中 n 是用于 Unicode 的一个十进制数字。例如,欧元符号的十进制引用是 €。通过在数字前面加上 x,也可以将码点指定为一个十六进制数字:&#xn 。例如,欧元符号的十六进制引用是 €。十六进制引用通常更方便,因为码点通常是用十六进制指定的。对于数字引用,前面的 0 被忽略。每个字符都必须单独转移或引用:例如,"!"" 是 "!"" (感叹号,双引号),而 "™" 是 "?"(商标)。

表 2 展示了一些示例字符和它们的 Unicode 码点以及 UTF 和两种遗留的西方码页中的字符编码。





回页首


Java String(和类和方法名等标识符)是用 UTF-16 编码的;但是源文件是用当前码页而不是 UTF-16 编码的。当用 javac 编译一个 Java 程序时,编译器将 String 文字从源文件的编码转换为 UTF-16。为了指定源文件使用另一种编码,可以使用 javac 选项 -encoding code-set-name 。该选项允许在标识符和文字字符串中使用一种不同的编码。

DB2 9 提供了一个助手类 com.ibm.db2.jcc.DB2Xml,这个类可以帮助在数据库与 Java 应用程序之间传输和转换数据。它对 XML 知道得更多;例如,有些方法可以根据实际的编码转换串行化 XML 文档的内部编码,使它们保持一致。



方法 返回类型 编码 添加含编码属性的 XML 声明?
getDB2String() String UTF-16
getDB2XmlString() String ISO-10646-UCS-2
getDB2Bytes() byte[ ] UTF-8
getDB2XmlBytes(String targetEncoding) byte[ ] As specified
getDB2AsciiStream() InputStream ASCII
getDB2XmlAsciiStream() InputStream ASCII
getDB2CharacterStream() java.io.Reader UTF-16
getDB2XmlCharacterStream() java.io.Reader ISO-10646-UCS-2
getDB2BinaryStream() InputStream UTF-8
getDB2XmlBinaryStream(String targetEncoding) InputStream As specified

DB2 9 附带了 2 种 JDBC 驱动程序,它们可以用三种不同的方式连接到 DB2(DB2 9 不支持 JDBC Type 3 驱动程序):

  • DB2 Driver for JDBC and SQLJ,一种通用的 JDBC 驱动程序,可以用以下方式连接:
    • JDBC Type 4 驱动程序
    • JDBC Type 2 驱动程序
  • DB2 JDBC Type 2 Driver(一种遗留驱动程序)

建议使用通用的 DB2 driver for JDBC and SQLJ。从 DB2, Version 8.2 开始,就不赞成使用遗留 Type 2 驱动程序。遗留 Type 2 JDBC 驱动程序不能与 DB2 类 com.ibm.db2.jcc.DB2Xml 一起使用,并且在某些 JDBC 方法中以不同的方式处理 XML。例如,一个 XML 列的 SELECT (没有显式的 XMLSERIALIZE())上的 get 方法(例如 ResultSet.getBinaryStream(column)ResultSet.getCharacterStream(column)ResultSet.getString(column))会添加一个 BOM 和 XML 声明到串行化 XML 中。要么内部编码(UTF-16)与实际编码不匹配,要么 BOM 被损坏,从而导致文档不可用。

关于 JDBC 驱动程序版本的更多信息,请参阅 表 4

对于任何类型的 JDBC 连接,如果要以当前用户之外的其它用户进行连接,则必须在连接 URL 或 getConnection()Properties 参数中指定所需的用户名和密码。

DB2 在 IBM\SQLLIB\samples\xml\java\jdbc 中提供了示例 JDBC 应用程序,例如 XmlInsert.java。如果使用它们进行试验,那么要小心,在默认情况下,这些应用程序用遗留的 Type 2 驱动程序连接到 DB2。(请查看 Util.java 文件中的助手类 Db。)为了用 Type 4 驱动程序进行连接,必须指定服务器、端口、用户和密码的命令行参数。 如果要看语法消息,可以用参数 -help 运行这个类:

prog_name -u2 [dbAlias] [userId passwd] (use universal JDBC type 2 driver)
prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)

例如:

java -cp ".;%CLASSPATH%" XmlInsert sample myhost 50000 myuser mypasswd

下载 小节中有演示 DB2、JDBC 和 DB2Xml 类如何处理编码的示例代码。





回页首


当将 XML 插入 DB2,并使用 SQLBindParameter() 将一个变量绑定到一个 XML 列时,CLI 根据下面表 5 中的输入规则确定 XML 的编码。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个主变量中时,数据将根据表 5 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



数据类型 输入中假定使用的编码 输出中使用的编码
SQL_C_CHAR 应用程序的码页 与输入相同
SQL_C_DBCHAR 应用程序的码页 与输入相同
SQL_C_WCHAR UCS-2 与输入相同
SQL_C_BINARY 读内部编码 UTF-8





回页首


当通过一个嵌入式 SQL(ESQL)主变量将 XML 插入 DB2 中时,XML 的编码根据表 6 中的输入规则来确定。如果编码由应用程序码页确定,但是文档还有一个内部编码(一个 BOM 或 XML 声明),则外部编码与内部编码必须一致。当从 DB2 中将 XML 取出到一个 ESQL 主变量中时,数据将根据表 6 使用一种内部编码(含编码属性的一个 XML 声明)来编码。



SQL TYPE IS 输入中假定使用的编码 输出中使用的编码
XML AS CLOBXML AS CLOB_FILE 应用程序的码页 与输入相同
XML AS DBCLOBXML AS DBCLOB_FILE 应用程序的码页 与输入相同
XML AS BLOBXML AS BLOB_FILE 读内部编码(注 1) UTF-8
char[] 之类的一个简单类型 应用程序的混合码页(注 2) 与输入相同

注 1: 如果一个 BLOB 类型的变量没有任何内部编码,则 DB2 假定其编码为 UTF-8。

注 2:为了通过一个简单类型(例如 char)变量插入 XML,可以使用 SQL 函数 XMLCAST(? AS XML) 将其映射到 XML。





回页首


  • 将字符串文字(例如提示和错误消息)从源代码中转移到某种属性或初始化文件中,或者转移到一个数据库表中。这样做便于将应用程序翻译成其它语言。但是,需要在应用程序中硬编码一两条错误消息,以防应用程序不能打开那个消息文件或者查询消息表。
  • 避免非 Unicode 字符集之间的译码,以防丢失目标字符集中没有的字符。
  • 对于不是用 Java 语言编写的应用程序,在应用程序环境中用不同的码页对它进行测试。您也许不能控制用户的码页。(Java 应用程序码页总是 UTF-16。)
  • 用一些非 ASCII 数据测试应用程序。码页 437、 1252、8859-1 和 1208(UTF-8 的编码)在前 128 个字节中都与 US-ASCII 匹配,所以 US-ASCII 数据在编码或译码方面出问题的几率更小。检查在译码时丢失的字符,这通常不会产生任何错误消息。
  • 使用通用 DB2 Driver for JDBC and SQLJ,而不是遗留的 Type 2 驱动程序。如果不能控制应用程序所使用的驱动程序,那么可以用生产中将使用的驱动程序类型对应用程序进行测试,避免那些不是在所有驱动程序类型中都能工作或者在不同驱动程序中有不同行为的方法。
  • 对于 C 应用程序,为了处理 char[] 数据类型中的 XML,使用 UTF-8 编码,因为它不包含 null(\0)作为有效字节。
  • 对于 CLI 和 ESQL 应用程序,要清楚 CLI 会返回使用内部编码的 XML 数据。如果进行译码,或者改变实际编码,则文档变得不可用。为了避免这一点,将应用程序变量绑定到 SQL_C_BINARY 类型;这样可以使数据保持使用 UTF 编码,从而避免从当前编码到本地码页的有损失的译码。
  • 对于将存放 UTF 字符的任何数据类型,要提供足够的空间,因为一个字符可能占多个字节。
阅读(201386) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~