`
Qieqie
  • 浏览: 340974 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

《碰到的一个编码问题》的回答:UTF-8的汉字字节!

阅读更多
埋伏:
1、UTF-8用几个字节表示一个汉字?
这各答案你可能了解,但也可能不了解,我敢打保票一半人会不清楚(包括特意查资料之前的我)。
了解这个对编程有什么影响?


以下我把对yoolywu的回答,转为帖子发表,以表重视。


yollywu的问:
引用
系统有两个子系统,一个是BS的,一个是delphi做的CS,中间的数据传输是通过XML进行传输的。在XML传输的功能实现后,要求对XML进行加密解密.加密解密算法是CS端用delphi写的,然后这边用JAVA写个同样的算法。现在碰到的一个问题是:
用该算法的时候,CS和BS各自都能够加解密,我这边的过程是这样的。。。。[但最后]中文始终是乱码
  
        StringBuffer strbuf = new StringBuffer();
	try {
		FileInputStream in = new FileInputStream(file);
		int size = 0;
		byte [] buf = new byte[1024];	
		while ((size=in.read(buf)) != -1) {
			strbuf.append(new String(buf,0,size));
		}
		
	} catch (FileNotFoundException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	} catch (IOException e1) {
		// TODO Auto-generated catch block
		e1.printStackTrace();
	}
       return strbuf;
          





Qieqie的答:



以下的代码是错误的:
StringBuffer strbuf = new StringBuffer();   
...
 strbuf.append(new String(buf,0,size));  


第一、
你应该使用ByteArrayOutputStream,将InputStream的字节全部读出来,然后转成byte[]数组,最后在根据你和对方协议规定的字符集合(假设你们规定的是UTF-8,如果没有规定,那么就补充上吧),将byte[]变成String: String theString = new String(bytes, "UTF-8")。
不加"UTF-8"的new String,将使用Java环境设置的字符集,没有特别设置的情况下也就是操作系统的字符集。这是不可靠的。

第二、
不能使用byte[]+StringBuffer:StringBuffer是针对char操作的(String也是)。读取byte时可能刚好把一个多字节的char分成前后两批加入StringBuffer。这样就破坏了char的完整性了。而如果你使用UTF-8编码的中文,你就会中招,导致乱码(其实是因为你的读取是由于byte失去原有顺序导致的,跟一般的乱码还不一样)
--
在UTF-8编码集中,每个汉字使用 3个字符表示! 实践证明:
1、创建一个UTF-8编码的文件:weare.txt
2、写入三个字:“我们是
3、运行以下代码:
public class UTF8 {

	public static void main(String[] args) throws IOException {
		String p = "weare.txt";
		InputStream in = new FileInputStream(p);
		int read = in.read(new byte[1204]);
		System.out.println(read);
		
	}
}

4、你会发现打印出来的是 9 !

所以,byte[]+StringBuffer的使用方式是错误的!

不过可以使用StringBuffer + bufferedReader.readLine(),读出一行行后再加入StringBuffer。
或者第2楼说的stringbuffer+reader.read(char[])的形式(毕竟错误是由于byte[]导致的,而非StringBuffer)




参考资料:

zh.wikipedia.org 写道

UTF-8 使用一至四个字节为每个字符编码。128 个 ASCII 字符(Unicode 范围由 U+0000 至 U+007F)只需一个字节,带有变音符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及马尔代夫语(Unicode 范围由 U+0080 至 U+07FF)需要二个字节,其他基本多文种平面(BMP)中的字符(CJK属于此类-Qieqie注)使用三个字节,其他 Unicode 辅助平面的字符使用四字节编码。


分享到:
评论
15 楼 tvjody 2007-08-20  
编码确实是个碍手的问题
14 楼 dogstar 2007-08-19  
utf-8表示英文用一个字节表示一个,和Ascii一样。表示汉字就不一定了。

UTF-8用1到6个字节编码UNICODE字符。如果UNICODE字符由2个字节表示,则编码成UTF-8很可能需要3个字节,而如果UNICODE 字符由4个字节表示,则编码成UTF-8可能需要6个字节。用4个或6个字节去编码一个UNICODE字符可能太多了,但很少会遇到那样的UNICODE 字符。
13 楼 hax 2007-08-19  
楼上的,你保存的文件可能带有BOM。
12 楼 wangbing111 2007-08-19  
引用

1、创建一个UTF-8编码的文件:weare.txt
2、写入三个字:“我们是”
3、运行以下代码:


代码
public class UTF8 {  
 
    public static void main(String[] args) throws IOException {  
        String p = "weare.txt";  
        InputStream in = new FileInputStream(p);  
        int read = in.read(new byte[1204]);  
        System.out.println(read);  
          
    }  
}  


4、你会发现打印出来的是 9 !



怎么我的文件是12个字节,打印结果是 12 ?
11 楼 bigpanda 2007-08-19  
可以看看我这篇博客:Utf-8编码是如何工作的 http://bigpanda.iteye.com/blog/31890
10 楼 yollywu 2007-08-18  
  实际上跟知道不知道UTF-8是几个字节一点关系都没有,最后把加解密算法重新都改成了对字节的操作。
  不过还是谢谢切切。
9 楼 Qieqie 2007-08-18  
yollywu 写道
  想说的一个问题是,协议方过来的是加密后十六进制数的一个大的字符串。文件格式我打开的时候另存默认格式是ANSI.


绕了一圈。被你提醒这一说,问题就不是出在编码上。而是这样:
1、密文单位是字节而非字符,那用什么编码读取都可以,UTF-8/GBK/ISOxxxx都可以,他们是兼容ISOxxxx的
2、既然是字节而非字符,那byte[]+StringBuffer不是问题的错误所在,用它读没有问题(肯定是对方的问题,刚好你们的协调人帮你发现了问题确实如此)
3、但,把密文转为明文后,再读取要用预先指定的字符集读取(此时不能使用byte[]+StringBuffer)
8 楼 Qieqie 2007-08-18  
LS的别ft,现实就是这样。

投入门贴的同学,认为这个知识简单,没有体认到“一个汉字用两个字节表示”的错误的结论几乎根深蒂固,因为根深蒂固,所以需要特别发帖指出。

(是否解决了yollywu的问题或者没解决可能不重要|因为也不是很了解他的问题。只是借yollywu的帖子作为引子而已,yollywu见谅)
7 楼 hax 2007-08-18  
我还以为utf8中中文是3个字节是基本常识呢,没想到还是有人不清楚。。。faint
6 楼 yollywu 2007-08-18  
谢谢各位,忙了我几天,一直不敢确定是哪边的错误,刚才被BOSS级人物解决了,他两边都懂,分析结果是那边算法有一处小问题造成的。
5 楼 yollywu 2007-08-18  
  我自己在读取密文的时候用的是这个
  
InputStreamReader read=null;
	 String line;
     try {
       read=new InputStreamReader (new FileInputStream(file),"UTF-8");
       BufferedReader fileBuffer=new BufferedReader(read);
		line=fileBuffer.readLine();
	    while (line != null){
	    	  strbuf.append(line);
	    	  strbuf.append("\n"); 
	          line = fileBuffer.readLine();
	          }
         } 
     catch (IOException e4){
         e4.printStackTrace();
      }
,按字节读是另外有个经验的人说的,但是我发现两种读法都没能改变结果,所以就没有换过来,我觉的主要问题还真有可能是算法上面,就是说我在debug的时候解密后的串转码UTF-8后,因为始终都有几个汉字不能正常显示。
4 楼 yollywu 2007-08-18  
  想说的一个问题是,协议方过来的是加密后十六进制数的一个大的字符串。文件格式我打开的时候另存默认格式是ANSI.
3 楼 fkpwolf 2007-08-18  
http://www.regexlab.com/zh/encoding.htm
2 楼 lujh99 2007-08-17  
如果是按字节来分批读取,不光是utf-8编码,gbk也是会有问题的,两个汉字是4个字节,而一个英文字母加一个汉字是3个字节,所以不可能每次都刚好从两个字符之间切开,除非所有字符都是汉字,可以按双数来取。
所以必须把字节流全部加载进来,整体一起转换成字符串。

如果事先知道字符编码,那么可以用楼上的简单方法,按字符来读取,读出来的都是完整的字符。

如果事先不知道编码格式,但是像xml文件头中注明了编码格式,那么可以按iso-8859-1的编码格式将读进来的字节流进行字符化,然后根据读到的encoding得到编码格式,按照正确的编码格式重新将读到的内容整体转换成正确的字符串。
因为iso-8859-1格式一个字节对应一个字符,并且每一个字节值都有一个对应的字符,将字符还原到字节时原来的值不会发生改变,所以按字节分批读取也不会破坏数据的完整性。并且gbk和utf-8都是兼容iso-8859-1的,即基本字符的编码是一样的,所以按iso-8859-1编码得到的encoding那一段字符是正确的,可识别的。
也可以只读取一个头部,找到正确的编码格式后,再用InputStreamReader按字符读取。
1 楼 birdjavaeye 2007-08-17  
对于这个例子,一个简单办法就是用InputStreamReader:
InputStreamReader in = new InputStreamReader(new FileInputStream(file), "UTF-8");
char[] buf ...
读取in到buf,再append到strbuf

相关推荐

    UTF-8汉字码表.txt

    在给定文件“UTF-8汉字码表.txt”的描述中提到的“utf-8中文汉字编码表”,主要关注的是如何用UTF-8编码来表示中文汉字。 #### 二、文件内容分析 文件中展示了一些具体的编码示例,从十六进制数字`20`到`7E`以及从...

    UTF-8 汉字码表

    ### UTF-8编码详解与汉字码表解析 #### UTF-8编码原理 UTF-8(Unicode Transformation Format - 8 bits)是一种变长字符编码,由Ken Thompson于1992年设计,旨在解决多语言环境下字符编码兼容性问题。其核心优势...

    UTF-8编码表

    如果UNICODE字符由2个字节表示,则编码成UTF-8很可能需要3个字节,而如果UNICODE字符由4个字节表示,则编码成UTF-8可能需要6个字节。用4个或6个字节去编码一个UNICODE字符可能太多了,但很少会遇到那样的UNICODE...

    UTF-8toGBK_labview编码gbk_LabVIEWUTF-8_utf-8toGbk_

    在IT行业中,字符编码是一个非常重要的概念,尤其是在处理多语言数据和跨平台通信时。UTF-8和GBK是两种常见..."UTF-8toGBK.vi"这个VI提供了一个实用的工具,可以帮助开发者解决在处理中文字符串时可能出现的编码问题。

    汉字字符编码(utf-8 unicode gb2312)

    3. **UTF-8**:是一种变长的Unicode编码格式,它可以使用1至4个字节来表示一个Unicode字符。对于常见的ASCII字符(如英文字符、数字、标点符号),UTF-8使用与ASCII相同的单字节编码,而对于非ASCII字符(如汉字),...

    UTF-8 Unicode GBK GB2312 编码之间的区别和联系

    4. **UTF-8**:Unicode Transformation Format - 8-bit,是Unicode的一种变长字符编码,使用1到4个字节表示一个字符。 5. **GBK**:全称为GB2312-80的扩展版,是中国大陆地区制定的汉字编码标准。 6. **GB2312**:...

    批量将文件编码方式由ansi转为utf-8

    ANSI是一种单字节编码,主要用于英文环境,而UTF-8是一种多字节编码,支持全球多种语言,包括中文。 标题"批量将文件编码方式由ansi转为utf-8"涉及到的是一个文件处理任务,即转换大量以ANSI编码存储的文件到UTF-8...

    UTF-8toGBK_labview编码gbk_LabVIEWUTF-8_utf-8toGbk_源码.zip

    例如,如果你需要从一个使用GBK编码的系统获取数据,而你的程序默认使用UTF-8编码,那么就需要进行这样的转换,以避免乱码问题。反之,如果你的数据需要发送给使用GBK编码的系统,你也需要做相应的转换。 总之,这...

    UTF-8.rar_Free!_UTF-8简体中文免费版_cmsware2.8.5pro

    对于英文字符,UTF-8编码与ASCII编码完全一致,占用一个字节,而对于中文字符,则通常需要三个字节。 【CMSware v2.8.5 UTF-8简体中文免费版】 CMSware是一款基于PHP开发的网站内容管理系统,版本号为2.8.5,特别...

    字符编码笔记:ASCII-Unicode和UTF-8

    字符编码笔记:ASCII、Unicode 和 UTF-8 本文主要介绍了字符编码的基本概念和历史发展过程,包括 ASCII 码、Unicode 和 UTF-8 的编码原理和特点。文章首先介绍了 ASCII 码的历史和编码原理,然后讨论了非 ASCII ...

    utf-8码转换器(转换成utf-8码)

    如果一个GBK编码的文本包含非GBK字符,使用UTF-8编码器读取会出现乱码。因此,通过转换器将GBK编码转换为UTF-8编码,可以确保文本在各种系统和语言环境中都能正确显示。 4. **编码转换工具的实现**: - 接收输入:...

    gb2312,utf-8,utf-8-bom等编码格式的互相转换

    UTF-8-BOM,全称是“UTF-8 Byte Order Mark”,它在UTF-8编码的文件开头添加了一个特殊的字节序列(0xEF, 0xBB, 0xBF)来标识该文件使用的是UTF-8编码。BOM主要用于帮助软件识别文件的编码,但并非所有UTF-8编码的...

    UTF-8编码转换器

    总的来说,“UTF-8编码转换器”是一个实用的工具,对于那些需要处理多种语言文本或者在不同系统间交换数据的人来说非常有价值。通过它可以轻松解决编码兼容性问题,使得数据在不同环境中的传输和使用更加顺畅。

    JAVA字符编码:Unicode,ISO-8859-1,GBK,UTF-8编码及相互转换

    UTF-8使用1到4个字节来表示一个字符,对于ASCII字符集中的字符,UTF-8与ASCII完全兼容。 #### 三、编码转换方法 在Java中,可以使用`String`类的方法来实现不同编码之间的转换。具体来说: - `getBytes(String ...

    ASP 生成静态网页(UTF-8)

    在涉及到UTF-8编码时,我们确保生成的静态网页能够正确显示多种语言的字符,特别是非英文字符,如中文、日文、韩文等。 在ASP中生成静态网页的过程主要包括以下步骤: 1. **动态数据获取**:首先,ASP脚本需要获取...

    utf-8 ansi 字符互转 工具

    例如“utf-8 ansi 字符互转 工具”就是这样一个软件,它能方便地帮助用户将文件或文本内容在UTF-8和ANSI编码之间进行转换。使用这类工具,用户通常只需选择输入文件、指定输出格式,然后点击转换按钮即可完成操作。 ...

    C#写的 GBK GB2312 UTF-8转换

    以下是一个简单的C#代码示例,演示如何将GBK编码的字符串转换为UTF-8: ```csharp using System; using System.Text; class Program { static void Main() { string gbkStr = "你好,世界"; // 假设这是GBK编码...

    解决Invalid byte 1 of 1-byte UTF-8 sequence

    描述中提到的“Invalid byte 1 of 1-byte UTF-8 sequence”错误提示意味着在尝试解码一个UTF-8编码的字节序列时,遇到了一个无效的字节。这通常是因为文件或数据流被错误地识别为不同的字符集,如GBK,导致解码失败...

    UTF-8中文字符表

    ### UTF-8中文字符表详解 #### 一、前言 在数字编码的世界里,UTF-8(Unicode Transformation Format-8 bits)作为一种重要的编码方式,被广泛应用于网页、数据库及各种文本处理系统中。UTF-8是Unicode的一种变长...

    gbk转换utf-8工具!绝对给力!

    ”暗示了这是一个专门用于处理字符编码转换问题的软件,主要功能是将GBK编码的文件或文本转换成UTF-8编码。GBK是GB2312编码的扩展,广泛应用于中文系统,而UTF-8则是国际通用的多语言编码方式,支持世界上几乎所有的...

Global site tag (gtag.js) - Google Analytics