【编码与乱码】(03)----String的toCharArray()方法

package example.encoding;

import java.io.UnsupportedEncodingException;

/**
 * The Class GetCharTest.
 */
public class GetCharTest {

    /**
     * The main method.
     * 
     * @param args the arguments
     */
    public static void main(String args[]) {
        String content = "中文";
        String defaultEncoding = System.getProperty("file.encoding");
        String defaultLnaguage = System.getProperty("user.language");
        System.out.println("System default encoding --- " + defaultEncoding);
        System.out.println("System default language --- " + defaultLnaguage);

        GetCharTest tester = new GetCharTest();
        tester.getCharWithDefaultEncoding(content);
        tester.getCharWithGivenEncoding(content, "ISO-8859-1");
        tester.getCharWithGivenEncoding(content, "GBK");
        tester.getCharWithGivenEncoding(content, "UTF-8");
    }

    /**
     * Gets the char with default encoding.
     * 
     * @param content the content
     * 
     * @return the char with default encoding
     */
    public void getCharWithDefaultEncoding(String content) {
        System.out.println("\nGet characters with default encoding\n");
        printCharArray(content);
    }

    /**
     * Gets the char with given encoding.
     * 
     * @param content the content
     * @param encoding the encoding
     * 
     * @return the char with given encoding
     */
    public void getCharWithGivenEncoding(String content, String encoding) {
        System.out.println("\nGet characters with given encoding : " + encoding
                + "\n");
        try {
            String encodedString = new String(content.getBytes(), encoding);
            printCharArray(encodedString);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    /**
     * Prints the char array.
     * 
     * @param inStr the in str
     */
    public void printCharArray(String inStr) {
        char[] charArray = inStr.toCharArray();

        for (int i = 0; i < inStr.length(); i++) {
            byte b = (byte) charArray[i];
            short s = (short) charArray[i];
            String hexB = Integer.toHexString(b).toUpperCase();
            String hexS = Integer.toHexString(s).toUpperCase();
            StringBuffer sb = new StringBuffer();

            // print char
            sb.append("char[");
            sb.append(i);
            sb.append("]='");
            sb.append(charArray[i]);
            sb.append("'\t");

            // byte value
            sb.append("byte=");
            sb.append(b);
            sb.append(" \\u");
            sb.append(hexB);
            sb.append('\t');

            // short value
            sb.append("short=");
            sb.append(s);
            sb.append(" \\u");
            sb.append(hexS);
            sb.append('\t');

            // Unicode Block
            sb.append(Character.UnicodeBlock.of(charArray[i]));

            System.out.println(sb.toString());
        }
        System.out.println("\nCharacters length: " + charArray.length);
    }

}

【1】在中文平台下,测试的结果如下:

System default encoding --- GBK
System default language --- zh

Get characters with default encoding

char[0]='中' byte=45 \u2D short=20013 \u4E2D CJK_UNIFIED_IDEOGRAPHS
char[1]='文' byte=-121 \uFFFFFF87 short=25991 \u6587 CJK_UNIFIED_IDEOGRAPHS

Characters length: 2

Get characters with given encoding : ISO-8859-1

char[0]='?' byte=-42 \uFFFFFFD6 short=214 \uD6 LATIN_1_SUPPLEMENT
char[1]='?' byte=-48 \uFFFFFFD0 short=208 \uD0 LATIN_1_SUPPLEMENT
char[2]='?' byte=-50 \uFFFFFFCE short=206 \uCE LATIN_1_SUPPLEMENT
char[3]='?' byte=-60 \uFFFFFFC4 short=196 \uC4 LATIN_1_SUPPLEMENT

Characters length: 4

Get characters with given encoding : GBK

char[0]='中' byte=45 \u2D short=20013 \u4E2D CJK_UNIFIED_IDEOGRAPHS
char[1]='文' byte=-121 \uFFFFFF87 short=25991 \u6587 CJK_UNIFIED_IDEOGRAPHS

Characters length: 2

Get characters with given encoding : UTF-8

char[0]='?' byte=-3 \uFFFFFFFD short=-3 \uFFFFFFFD SPECIALS
char[1]='?' byte=-3 \uFFFFFFFD short=-3 \uFFFFFFFD SPECIALS
char[2]='?' byte=-3 \uFFFFFFFD short=-3 \uFFFFFFFD SPECIALS
char[3]='?' byte=-3 \uFFFFFFFD short=-3 \uFFFFFFFD SPECIALS

Characters length: 4

【2】在英文平台下,测试的结果如下:


System default encoding --- Cp1252
System default language --- en

Get characters with default encoding

char[0]='?' byte=45 \u2D short=20013 \u4E2D CJK_UNIFIED_IDEOGRAPHS
char[1]='?' byte=-121 \uFFFFFF87 short=25991 \u6587 CJK_UNIFIED_IDEOGRAPHS

Characters length: 2

Get characters with given encoding : ISO-8859-1

char[0]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN
char[1]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN

Characters length: 2

Get characters with given encoding : GBK

char[0]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN
char[1]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN

Characters length: 2

Get characters with given encoding : UTF-8

char[0]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN
char[1]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN

Characters length: 2

【结论】


和getBytes(encoding)不同,toCharArray()返回的是"自然字符"。但是这个"自然字符"的数目和内容却是由原始的编码方式决定的。来看看里面是如何进行字符串的操作的:
 
 String encodedString = new String(content.getBytes(), encoding);
 char[] charArray = inStr.toCharArray();

可以看到系统首先对原始字符串按照默认的编码方式进行编码,得到一个字节数组,然后按照指定的新的编码方式进行解码,得到新的编码后的字符串。再转换成对应的字符数组。

由于在中文平台下,默认的字符集编码是GBK,于是content.getBytes()得到的是什么呢?就是下面这4个字节:

 byte[0] = -42 hex string = ffffffd6
 byte[1] = -48 hex string = ffffffd0
 byte[2] = -50 hex string = ffffffce
 byte[3] = -60 hex string = ffffffc4

如果新的encoding是GBK,那么经过解码后,由于一个字符用2个字节表示。于是最终的结果就是:
 char[0]='中' --- byte[0] + byte[1]
 char[1]='文' --- byte[2] + byte[3]

如果新的encoding是ISO-8859-1,那么经过解码后,由于一个字符用1个字节表示,于是原来本应该2个字节一起解析的变成单个字节解析,每个字节都代表了一个汉字字符的一半。这一半的字节在ISO-8859-1中找不到对应的字符,就变成了"?"了,最终的结果:
 char[0]='?' ---- byte[0]
 char[1]='?' ---- byte[1]
 char[2]='?' ---- byte[2]
 char[3]='?' ---- byte[3]

如果新的encoding是UTF-8,那么经过解码后,由于一个字符用3个字节表示,于是原来4个字节的数据无法正常的解析成UTF-8的数据,最终的结果也是每一个都变成"?"。
 char[0]='?' ---- byte[0]
 char[1]='?' ---- byte[1]
 char[2]='?' ---- byte[2]
 char[3]='?' ---- byte[3]

如果是在英文平台下,由于默认的编码方式是Cp1252,于是content.getBytes()得到的字节都是被截去一半的残留字符,所以我们看到在英文平台下,不论指定的encoding是GBK、UTF-8,其结果和ISO-8859-1都是一样的。

记住:

这个方法再次证明了String的getBytes()方法的危险性,如果我们使用new String(str.getBytes(), encoding)对字符串进行重新编码解码时,我们一定要清楚str.getBytes()方法返回的字节数组的长度、内容到底是什么,因为在接下来使用新的encoding进行编码解码时,Java并不会自动地对字节数组进行扩展以适应新的encoding。而是按照新的编码方法直接对该字节数组进行解析。

于是结果就像上面的例子一样,同样是4个原始字节,有些每2个一组进行解析,有些每个一组进行解析,有些每3个一组进行解析。其结果就只能看那种编码方式合适了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
apache commons-io-2.CHM帮助文档 一、FileUtils 打开FileUtils的api文档,我们抽出一些工作中比较常用的方法,进行总结和讲解。总结如下: cleanDirectory:清空目录,但不删除目录。 contentEquals:比较两个文件的内容是否相同。 copyDirectory:将一个目录内容拷贝到另一个目录。可以通过FileFilter过滤需要拷贝的 文件。 copyFile:将一个文件拷贝到一个新的地址。 copyFileToDirectory:将一个文件拷贝到某个目录下。 copyInputStreamToFile:将一个输入流中的内容拷贝到某个文件。 deleteDirectory:删除目录。 deleteQuietly:删除文件。 listFiles:列出指定目录下的所有文件。 openInputSteam:打开指定文件的输入流。 readFileToString:将文件内容作为字符串返回。 readLines:将文件内容按行返回到一个字符串数组中。 size:返回文件或目录的大小。 write:将字符串内容直接写到文件中。 writeByteArrayToFile:将字节数组内容写到文件中。 writeLines:将容器中的元素的toString方法返回的内容依次写入文件中。 writeStringToFile:将字符串内容写到文件中。 二、IOUtils 打开IOUtils的api文档,我们发现它的方法大部分都是重载的。所以,我们理解它的方法并不是难事。因此,对于方法的用法总结如下: 1. buffer方法:将传入的流进行包装,变成缓冲流。并可以通过参数指定缓冲大小。 2. closeQueitly方法:关闭流。 3. contentEquals方法:比较两个流中的内容是否一致。 4. copy方法:将输入流中的内容拷贝到输出流中,并可以指定字符编码。 5. copyLarge方法:将输入流中的内容拷贝到输出流中,适合大于2G内容的拷贝。 6. lineIterator方法:返回可以迭代每一行内容的迭代器。 7. read方法:将输入流中的部分内容读入到字节数组中。 8. readFully方法:将输入流中的所有内容读入到字节数组中。 9. readLine方法:读入输入流内容中的一行。 10. toBufferedInputStream,toBufferedReader:将输入转为带缓存的输入流。 11. toByteArray,toCharArray:将输入流的内容转为字节数组、字符数组。 12. toString:将输入流或数组中的内容转化为字符串。 13. write方法:向流里面写入内容。 14. writeLine方法:向流里面写入一行内容。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欧米优

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值