`
talentluke
  • 浏览: 604888 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Java中文&编码问题小结

 
阅读更多

摘自 http://www.blogjava.net/zhugf000/archive/2005/10/09/15068.html

Java字符编码转换过程说明

 

 

javacn_fig1.gif 

常见问题

 

 

javacn_fig2.gif 

JVM

JVM启动后,JVM会设置一些系统属性以表明JVM的缺省区域。

user.language,user.region,file.encoding等。可以使用System.getProperties()详细查看所有的系统属性。

 

如在英文操作系统(UNIX)下,可以使用如下属性定义强制指定JVM为中文环境 -Dclient.encoding.override=GBK -Dfile.encoding=GBK -Duser.language=zh -Duser.region=CN

 

.java-->.class编译

说明:一般javac根据当前os区域设置,自动决定源文件的编码.可以通过-encoding强制指定.

 

错误可能:

1 gbk编码源文件在英文环境下编译,javac不能正确转换.曾见于java/jsp在英文unix. 检测方法:\u4e00格式的汉字,绕开javac编码,再在jvm,将汉字作为int打印,看值是否相等;或直接以UTF-8编码打开.class文件,看看常量字符串是否正确保存汉字。

 

文件读写

外部数据如文件经过读写和转换两个步骤,转为jvm所使用字符。InputStream/OutputStream用于读写原始外部数据,Reader/Writer执行读写和转换两个步骤。

 

1 文件读写转换由java.io.Reader/Writer执行;输入输出流 InputStream/OutputStream  处理汉字不合适,应该首选使用Reader/Writer,如 FileReader/FileWriter

 

2 FileReader/FileWriter使用JVM当前编码读写文件.如果有其它编码格式,使用InputStreamReader/OutputStreamWriter

 

3 PrintStream有点特殊,它自动使用jvm缺省编码进行转换。

 

 

读取.properties文件

.propeties文件由Properties类以iso8859-1编码读取,因此不能在其中直接写汉字,需要使用JDK native2ascii工具转换汉字为\uXXXX格式。命令行:native2ascii –encoding GBK inputfile outputfile

 

读取XML文件

1 XML文件读写同于文件读写,但应注意确保XML头中声明如<? xml version=”1.0” encoding=”gb2312” ?>与文件编码保持一致。

 

2 javax.xml.SAXParser类接受InputStream作为输入参数,对于Reader,需要用org.xml.sax.InputSource包装一下,再给SAXParser

 

3 对于UTF-8编码 XML,注意防止编辑器自动加上\uFFFE BOM, xml parser会报告content is not allowed in prolog

 

 

字节数组

1 使用 new String(byteArray,encoding)   String.getBytes(encoding)  在字节数组和字符串之间进行转换

 

也可以用ByteArrayInputStream/ByteArrayOutputStream转为流后再用InputStreamReader/OutputStreamWriter转换。

 

错误编码的字符串(iso8859-1转码gbk)

如果我们得到的字符串是由错误的转码方式产生的,例如:对于gbk中文,由iso8859-1方式转换,此时如果用调试器看到的字符串一般是的样子,长度一般为文本的字节长度,而非汉字个数。

 

可以采用如下方式转为正确的中文:

text = new String( text.getBytes(“iso8859-1”),”gbk”);

 

JDBC

转换过程由JDBC Driver执行,取决于各JDBC数据库实现。对此经验尚积累不够。

 

1 对于ORACLE数据库,需要数据库创建时指定编码方式为gbk,否则会出现汉字转码错误

2 对于 SQL Server 2000 ,最好以nvarchar/nchar类型存放文本,即不存在中文/编码转换问题。

3 连接 Mysql,将 connectionString 设置成 encoding gb2312

 String connectionString  = "jdbc:mysql://localhost/test?useUnicode=true&characterEncoding=gb2312";

 

WEB/Servlet/JSP

1 对于JSP,确定头部加上 <%@ page contentType="text/html;charset=gb2312"%>这样的标签。

2 对于Servlet,确定设置setContentType (“text/html; charset=gb2312”),以上两条用于使得输出汉字没有问题。

3 为输出HTML head中加一个 <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> ,让浏览器正确确定HTML编码。

 

4 Web应用加一个Filter,确保每个Request明确调用setCharacterEncoding方法,让输入汉字能够正确解析。

 

 

import java.io.IOException;

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.UnavailableException;

import javax.servlet.http.HttpServletRequest;

 

/**

 * Example filter that sets the character encoding to be used in parsing the

 * incoming request

 */

public class SetCharacterEncodingFilter

    implements Filter {

  public SetCharacterEncodingFilter()

  {}

  protected boolean debug = false;

  protected String encoding = null;

  protected FilterConfig filterConfig = null;

  public void destroy() {

    this.encoding = null;

    this.filterConfig = null;

  }

 

  public void doFilter(ServletRequest request, ServletResponse response,

                       FilterChain chain) throws IOException, ServletException {

//    if (request.getCharacterEncoding() == null)

//    {

//      String encoding = getEncoding();

//      if (encoding != null)

//        request.setCharacterEncoding(encoding);

//

//    }

      request.setCharacterEncoding(encoding);

      if ( debug ){

        System.out.println( ((HttpServletRequest)request).getRequestURI()+"setted to "+encoding );

      }

    chain.doFilter(request, response);

  }

 

  public void init(FilterConfig filterConfig) throws ServletException {

    this.filterConfig = filterConfig;

    this.encoding = filterConfig.getInitParameter("encoding");

    this.debug = "true".equalsIgnoreCase( filterConfig.getInitParameter("debug") );

  }

 

  protected String getEncoding() {

    return (this.encoding);

  }

}

 

 

web.xml中加入:

 

  <filter>

    <filter-name>LocalEncodingFilter</filter-name>

    <display-name>LocalEncodingFilter</display-name>

    <filter-class>com.ccb.ectipmanager.request.SetCharacterEncodingFilter</filter-class>

    <init-param>

      <param-name>encoding</param-name>

      <param-value>gb2312</param-value>

    </init-param>

    <init-param>

      <param-name>debug</param-name>

      <param-value>false</param-value>

    </init-param>

  </filter>

 

   <filter-mapping>

    <filter-name>LocalEncodingFilter</filter-name>

    <url-pattern>/*</url-pattern>

  </filter-mapping>

 

5 用于Weblogicvedor-specific):

其一:web.xml里加上如下脚本:

<context-param>

  <param-name>weblogic.httpd.inputCharset./*</param-name>

  <param-value>GBK</param-value>

</context-param>

其二(可选)在weblogic.xml里加上如下脚本:

<charset-params>

  <input-charset>

      <resource-path>/*</resource-path>

      <java-charset-name>GBK</java-charset-name>

  </input-charset>

</charset-params>

 

SWING/AWT/SWT

对于SWING/AWTJava会有些缺省字体如Dialog/San Serif,这些字体到系统真实字体的映射在$JRE_HOME/lib/font.properties.XXX文件中指定。排除字体显示问题时,首先需要确定JVM的区域为zh_CN,这样font.properties.zh_CN文件才会发生作用。对于 font.properties.zh_CN , 需要检查是否映射缺省字体到中文字体如宋体。

 

Swing中,Java自行解释TTF字体,渲染显示;对于AWT,SWT显示部分交由操作系统。首先需要确定系统装有中文字体。

 

1 汉字显示为,一般为显示字体没有使用中文字体,因为Java对于当前字体显示不了的字符,不会像Windows一样再采用缺省字体显示。

2 部分不常见汉字不能显示,一般为显示字库中汉字不全,可以换另外的中文字体试试。

3 对于AWT/SWT,首先确定JVM运行环境的区域设置为中文,因为此处设计JVM与操作系统api调用的转换问题,再检查其它问题。

 

JNI

JNIjstringUTF-8编码给我们,需要我们自行转为本地编码。对于Windows,可以采用WideCharToMultiByte/MultiByteToWideChar函数进行转换,对于Unix,可以采用iconv库。

 

这里从SUN jdk 1.4 源代码中找到一段使用jvm String 对象的getBytes的转换方式,相对简单和跨平台,不需要第三方库,但速度稍慢。函数原型如下:

 

/* Convert between Java strings and i18n C strings */

JNIEXPORT jstring

NewStringPlatform(JNIEnv *env, const char *str);

 

JNIEXPORT const char *

GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy);

 

JNIEXPORT jstring JNICALL

JNU_NewStringPlatform(JNIEnv *env, const char *str);

 

JNIEXPORT const char * JNICALL

JNU_GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy);

 

JNIEXPORT void JNICALL

JNU_ReleaseStringPlatformChars(JNIEnv *env, jstring jstr, const char *str);

 

 

附件jni_util.h,jni_util.c

 

 

 

TUXEDO/JOLT

JOLT对于传递的字符串需要用如下进行转码

new String(ls_tt.getBytes("GBK"),"iso8859-1")

 

对于返回的字符串

new String(error_message.getBytes("iso8859-1"),"GBK");

jolt 的系统属性 bea.jolt.encoding不应该设置,如果设置,JSH会报告说错误的协议.

 

 

JDK1.4/1.5新增部分

字符集相关类(Charset/CharsetEncoder/CharsetDecoder)

jdk1.4开始,对字符集的支持在java.nio.charset包中实现。

 

常用功能:

1 列出jvm所支持字符集:Charset.availableCharsets()

2 能否对看某个Unicode字符编码,CharsetEncoder.canEncode()

 

Unicode Surrogate/CJK EXT B

Unicode 范围一般所用为\U0000-\UFFFF范围,jvm使用1char就可以表示,对于CJK EXT B区汉字,范围大于\U20000,则需要采用2char方能表示,此即Unicode Surrogate。这2char的值范围落在Character.SURROGATE 区域内,用Character.getType()来判断。

 

jdk 1.4尚不能在Swing中正确处理surrogate区的Unicode字符,jdk1.5可以。对于CJK EXT B区汉字,目前可以使用的字库为宋体-方正超大字符集”,Office安装。

 

常见问题

JVM下,用System.out.println不能正确打印中文,显示为???

System.out.printlnPrintStream,它采用jvm缺省字符集进行转码工作,如果jvm的缺省字符集为iso8859-1,则中文显示会有问题。此问题常见于Unix下,jvm的区域没有明确指定的情况。

 

在英文UNIX环境下,System.out.println能够正确打印汉字,但是内部处理错误

可能是汉字在输入转换时,就没有正确转码:

gbk文本à(iso8859-1转码)àjvm char(iso8859-1编码汉字)à (iso8859-1转码)à输出。

gbk汉字经过两次错误转码,原封不动的被传递到输出,但是在jvm中,并未以正确的unicode编码表示,而是以一个汉字字节一个char的方式表示,从而导致此类错误。

 

 

GB2312-80GBKGB18030-2000 汉字字符集

 

GB2312-80 是在国内计算机汉字信息技术发展初始阶段制定的,其中包含了大部分常用的一、二级汉字,和 9 区的符号。该字符集是几乎所有的中文系统和国际化的软件都支持的中文字符集,这也是最基本的中文字符集。其编码范围是高位0xa10xfe,低位也是 0xa1-0xfe;汉字从 0xb0a1 开始,结束于 0xf7fe

 

GBK GB2312-80 的扩展,是向上兼容的。它包含了 20902 个汉字,其编码范围是 0x8140-0xfefe,剔除高位 0x80 的字位。其所有字符都可以一对一映射到 Unicode 2.0,也就是说 JAVA 实际上提供了 GBK 字符集的支持。这是现阶段 Windows 和其它一些中文操作系统的缺省字符集,但并不是所有的国际化软件都支持该字符集,感觉是他们并不完全知道 GBK 是怎么回事。值得注意的是它不是国家标准,而只是规范。随着 GB18030-2000国标的发布,它将在不久的将来完成它的历史使命。

 

GB18030-2000(GBK2K) GBK 的基础上进一步扩展了汉字,增加了藏、蒙等少数民族的字形。GBK2K 从根本上解决了字位不够,字形不足的问题。它有几个特点,

 

它并没有确定所有的字形,只是规定了编码范围,留待以后扩充。

编码是变长的,其二字节部分与 GBK 兼容;四字节部分是扩充的字形、字位,其编码范围是首字节 0x81-0xfe、二字节0x30-0x39、三字节 0x81-0xfe、四字节0x30-0x39

 

UTF-8/UTF-16/UTF-32

 

UTF,即Unicode Transformer Format,是Unicode代码点(code point)的实际表示方式,按其基本长度所用位数分为UTF-8/16/32。它也可以认为是一种特殊的外部数据编码,但能够与Unicode代码点做一一对应。

 

UTF-8是变长编码,每个Unicode代码点按照不同范围,可以有1-3字节的不同长度。

UTF-16长度相对固定,只要不处理大于\U200000范围的字符,每个Unicode代码点使用16位即2字节表示,超出部分使用两个UTF-164字节表示。按照高低位字节顺序,又分为UTF-16BE/UTF-16LE

UTF-32长度始终固定,每个Unicode代码点使用32位即4字节表示。按照高低位字节顺序,又分为UTF-32BE/UTF-32LE

 

UTF编码有个优点,即尽管编码字节数不等,但是不像gb2312/gbk编码一样,需要从文本开始寻找,才能正确对汉字进行定位。在UTF编码下,根据相对固定的算法,从当前位置就能够知道当前字节是否是一个代码点的开始还是结束,从而相对简单的进行字符定位。不过定位问题最简单的还是UTF-32,它根本不需要进行字符定位,但是相对的大小也增加不少。

 

 

关于GCJ JVM

GCJ并未完全依照sun jdk的做法,对于区域和编码问题考虑尚不够周全。GCJ启动时,区域始终设为en_US,编码也缺省为iso8859-1。但是可以用Reader/Writer做正确编码转换。

分享到:
评论

相关推荐

    Java中文编码问题小结

    Java中的中文编码问题是一个复杂而常见的议题,尤其是在跨平台开发中。本文主要涵盖了Java处理中文字符编码的关键点,包括Java虚拟机(JVM)的初始配置、编译过程中的编码设置、文件读写操作、XML文件处理以及字符串...

    web编码问题小结.doc

    本文档《web编码问题小结》详细总结了Java开发中可能遇到的各种编码问题及其解决方案,覆盖了数据库、Cookie、静态页面、POST与GET请求等多种场景。 #### 数据库的中文问题 数据库的中文问题主要源于数据库与应用...

    JAVA IO流小结

    JAVA IO流小结 JAVA IO流是指Java语言中用来实现输入/输出操作的机制。IO流是指任何有能力产出数据的数据源对象或者有能力接收数据的数据源对象。他屏蔽了实际的I/O设备处理数据的细节。 一、流的定义和分类 流是...

    java小结

    #### 小结 通过以上内容,我们对Java的基础知识有了更深入的理解。了解这些基础知识对于编程非常重要,特别是对于初学者来说。掌握了这些概念后,你可以更好地理解和编写Java代码,同时也能避免一些常见的错误和...

    java_文件复制(带有编码类型)

    小结 在本文中,我们讨论了如何使用 Java 将文件从一个位置复制到另一个位置,并且带有编码类型。我们学习了使用 BufferedWriter 和 BufferedReader 实现文件复制的方法,以及使用 OutputStreamWriter 实现文件复制...

    core java 小结

    它包括ASCII、ISO8859-1、GBK(GB2312)等编码,其中,中文字符在Unicode中占用3个字节。Unicode与UTF的关系在于,UTF是Unicode的传输格式,用于网络传输。 #### 九、Boolean类型与逻辑运算 Java中的`boolean`类型...

    jsp中文乱码问题小结

    总结来说,解决JSP中文乱码问题需要从多角度入手,包括客户端的解码与编码设置、服务器端的请求处理和响应输出,以及数据库的字符集配置。正确理解和应用这些策略,可以有效避免和解决中文乱码问题,确保Web应用的...

    基于java的商品信息管理系统--大学本科Java基础

    学会编制结构清晰、风格良好适当的java语言程序,从而具备解决综合性实际问题的能力1.2课程设计内容和要求1、系统需实现基础功能:增、删、改、查。2、学生可自行添加完善功能。3、界面美观得体,(1)登陆界面醒目...

    java开发经验小结

    【Java开发经验总结】 在Java开发中,良好的编程习惯和高效的设计原则对于代码质量和性能至关重要。以下是一些从编码规范到性能优化的关键知识点: 1. **编码规范**:规范的编码习惯是提升代码可读性和可维护性的...

    Thinking in java4(中文高清版)-java的'圣经'

    + 和 += 3.14 使用操作符时常犯的错误 3.15 类型转换操作符 3.15.1 截尾和舍入 3.15.2提升 3.16 Java没有“sizeof” 3.17 操作符小结 3.18 总结 第4章 控制执行流程 4.1 true和false 4.2 if-else 4.3 迭代 4.3.1 do-...

    java小结txt文档

    ### Java与JSP知识点解析 ...通过以上分析,我们可以深入理解Java中DAO模式的应用、数据库连接管理、Web应用中的编码问题以及Servlet的工作机制和接口体系,这些都是Java Web开发中的核心知识点。

    Java数据结构和算法中文第二版

    小结 问题 第2章 数组 Array专题Applet Java中数组的基础知识 将程序划分成类 类接口 Ordered专题applet 有序数组的Java代码 对数 存储对象 大O表示法 为什么不用数组表示一切? 小结 问题 实验 编程...

    Java数据结构和算法中文第二版(1)

    小结 问题 第2章 数组 Array专题Applet Java中数组的基础知识 将程序划分成类 类接口 Ordered专题applet 有序数组的Java代码 对数 存储对象 大O表示法 为什么不用数组表示一切? 小结 问题 实验 ...

    华为OD机试C卷- 模拟数据序列化传输(Java & JS & Python & C & C++).md-私信看全套

    #### 小结 本题目考察了序列化与反序列化的基本概念,并通过具体的编码和解码任务让参与者深入理解这一技术的实际应用。在实现过程中需要注意边界条件和异常处理,确保程序的健壮性和准确性。无论是 Java 还是 ...

    Java高级程序设计实战教程第一章-Java编码规范.pptx

    Java编码规范是编程实践中至关重要的一个环节,它旨在提高代码质量、增强可读性、促进团队协作,并降低维护成本。本章主要分为六个部分:应用场景、相关知识、任务实施、拓展知识、拓展训练和课后小结。 首先,应用...

    Java学习IO流小结--字符流

    ### Java学习IO流小结——字符流 #### 知识点概述 在Java中,处理文件和数据流是一项基本而重要的任务。IO流是Java语言中处理输入/输出的重要工具,它包括字节流和字符流两大类。本文将重点讨论字符流的相关概念...

    JSP中文乱码问题解决方法小结

    为避免这个问题,需要在发送请求前使用`java.net.URLEncoder.encode()`对中文参数进行编码,例如`RearshRes.jsp?keywords=" + java.net.URLEncoder.encode(keywords, "UTF-8")`。在接收端,使用`new String(request....

    java数据结构与算法第二版

    小结 问题 第2章 数组 Array专题Applet Java中数组的基础知识 将程序划分成类 类接口 Ordered专题applet 有序数组的Java代码 对数 存储对象 大O表示法 为什么不用数组表示一切? 小结 问题 实验 编程...

    Java数据结构和算法(第二版)

    小结 问题 第2章 数组 Array专题Applet Java中数组的基础知识 将程序划分成类 类接口 Ordered专题applet 有序数组的Java代码 对数 存储对象 大O表示法 为什么不用数组表示一切? 小结 问题 实验 编程作业 第3章 ...

    jsp中影响编码的属性及其设置小结

    在JavaServer Pages (JSP) 开发中,正确设置编码属性对于确保文本数据在不同环节间的正确处理至关重要。本文将详细解析JSP中影响编码的属性及其设置,并探讨它们之间的相互影响和作用顺序。 首先,我们需要理解几个...

Global site tag (gtag.js) - Google Analytics