字符串编码浅析


title: 字符串编码理解
date: 2019-10-23
time: 11:09:00
categories: Java
toc: true
tag: 编码 字符串


[TOC]



编码(字符集)与编码格式

编码(字符集)是字符与二进制代码一一对应的关系 可以理解为一个字典

GBK GB2312 Unicode等是编码

UTF-8 UTF-16 是Unicode编码的实现格式

Unicode编码

Unicode 只是一个字符集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储

比如,汉字严的 Unicode 是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说,这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多
Unicode没有规定编码的存储方式 对于英文字符用3或4个字节表示过于浪费 故衍生出了UTF-8等Unicode的编码格式

GBK编码的编码格式就是GBK

UTF-8

UTF-8 是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度
UTF-8 的编码规则

  1. 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的
  2. 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码

Java中String编码

Java中String在程序运行中时即在内存中时均为Unicode编码

深入理解String.getBytes()

​ 由于在Java中String一直是Unicode的编码故在数据传输时需要将其以指定编码格式转为字节数组以使字符串能正确的持久化[1] (被写入文件或在网络上传输)
​ 绝大部分的乱码问题都是因为字符串的编码[2]解码[3]出问题了

在Java中getBytes有三个重载的方法 分别是:

  1. getBytes() 使用默认的字符集编码[2] 默认字符集在Java中可用System.getProperty("file.encoding")Charset.defaultCharset() 在中文系统中一般是GBK
  2. getBytes(Charset charset) 使用给定的charset将该String编码[2]为字节序列,将结果存储到新的字节数组中
  3. getBytes(String charsetName) 使用命名的字符集将此 String编码[2]为字节序列,将结果存储到新的字节数组中

已弃用的不在此说明

代码示例

public static void main(String[] args) throws UnsupportedEncodingException {
    String string = "码农爱撸猫";
    // 1
    printBytes(string.getBytes());
    // 2
    printBytes(string.getBytes("GBK"));
    // 3
    printBytes(string.getBytes(StandardCharsets.UTF_8));
}
private static void printBytes(byte[] bytes){
    System.out.println();
    for (byte bt : bytes){
        System.out.print("["+bt+"]");
    }
    System.out.println();
}
// 输出如下
/*
// 1
[-25][-96][-127][-27][-122][-100][-25][-120][-79][-26][-110][-72][-25][-116][-85]
// 2 使用GBK能够获取到正确的编码说明 String 一直是Unicode编码
[-62][-21][-59][-87][-80][-82][-33][-93][-61][-88]
// 3 和 1 的输出一致说明当前默认字符集是UTF-8
[-25][-96][-127][-27][-122][-100][-25][-120][-79][-26][-110][-72][-25][-116][-85]
*/

深入理解String由byte[]构建的构造函数

  1. String(byte[] bytes)
    通过使用平台的默认字符集解码指定的字节数组来构造新的 String
  2. String(byte[] bytes, Charset charset)
    构造一个新的String由指定用指定的字节的数组解码charset
  3. String(byte[] bytes, String charsetName)
    构造一个新的String由指定用指定的字节的数组解码charset

​ 实际应用中经常有这样的需求将指定编码格式的字符串转为另一种编码格式字符串,接到需求后马上打开百度搜索Java 字符串编码转换
​ 比如 要求将GBK编码的字符串转为UTF-8编码的字符串 网络上流行的解决 如下
String newStr = new String(oldStr.getBytes("GBK"),"UTF-8"); 这段代码的实际意思是将oldStr以GBK编码格式编码得到GBK编码格式的字节数组,然后以UTF-8的编码格式解码成字符串

public class CharestTrain3 {
    // 编码转换测试
    public static void main(String[] args) throws IOException {
        String content = "码农爱撸猫";
        String pathGBK = "c:/temp/testGBK.txt";
        String pathUTF = "c:/temp/testUTF.txt";
        String encodingUTF = "UTF-8";
        String encodingGBK = "GBK";
        // 使用GBK编码将原始内容写入文件
        write(pathGBK, content, encodingGBK);
        // 读取GBK编码文件
        String gbkStr = read(pathGBK, encodingGBK);
        // 输出GBK编码文件字符串
        System.out.println("gbkStr:"+gbkStr);
        // 将GBK编码文件(testGBK.txt)内容以UTF-8编码写入文件(testUTF.txt)
        write(pathUTF, gbkStr, encodingUTF);
        // 读取UTF编码文件
        String utfStr = read(pathUTF, encodingUTF);
        // 输出UTF编码文件字符串
        System.out.println("utfStr:"+utfStr);
    }
    // 读文件
    private static String read(String path, String encoding) throws IOException {
        StringBuilder content = new StringBuilder();
        File file = new File(path);
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), encoding));
        String line;
        while ((line = reader.readLine()) != null) {
            content.append(line).append("\n");
        }
        reader.close();
        return content.toString();
    }
    // 写文件
    private static void write(String path, String content, String encoding) throws IOException {
        File file = new File(path);
        if (file.delete()){
            file.createNewFile();
        }
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), encoding));
        writer.write(content);
        writer.close();
    }
}
// 输出
/*
gbkStr:码农爱撸猫
utfStr:码农爱撸猫
*/

System.out.print(x) 输出乱码

在运行以下代码时 加入如下命令-Dfile.encoding=GBK可以看到输出是乱码 因为汉字在GBK字符集中没有对应的编码 导致在调试时可以看到汉字能正确显示 但在console的输出中乱码, 当你在运行时加入-Dfile.encoding=UTF-8则调试与输出都能正常显示 由此可知System.out.print()在输出字符时使用了运行时的字符集输出了字符

 public static void main(String[] args){
    String str = "㑾";
    System.out.println(str);
}
// 输出
// ?
System.out.print(x)

CXF WebService框架

参数字符串 持久化传输时使用的UTF-8编码




  1. 持久化:数据持久化就是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型的统称.数据模型可以是任何数据结构或对象模型,存储模型可以是关系模型、XML、二进制流等
    数据持久化百度百科点击此处

  2. 编码:将字符串转为指定编码格式的字节数组

  3. 解码:将字节数组以指定编码格式转为字符串

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,165评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,503评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,295评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,589评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,439评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,342评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,749评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,397评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,700评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,740评论 2 313
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,523评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,364评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,755评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,024评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,297评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,721评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,918评论 2 336

推荐阅读更多精彩内容