【Java编程高级进阶】java 获取 string 字符串的编码详解

简介: 刚刚研究的一个问题“Java同样的汉字在服务器和本地的电脑上URLencode 出来的结果不一致”也涉及了字符串的编码格式。最简单的方法就是:Charset.defaultCharset();Servlet中可以使用:request.

刚刚研究的一个问题“Java同样的汉字在服务器和本地的电脑上URLencode 出来的结果不一致”也涉及了字符串的编码格式。

最简单的方法就是:Charset.defaultCharset();

Servlet中可以使用:request.getCharacterEncoding();

也可以使用上文提到的,不过也不那么简单:

dfltEncName = (String)AccessController.doPrivileged(new GetPropertyAction("file.encoding")); 

也有一些其它方式可以参考,如下面这个就比较麻烦了!

public static String getEncoding(String str) {      
       String encode = "GB2312";      
      try {      
          if (str.equals(new String(str.getBytes(encode), encode))) {      //判断是不是GB2312
               String s = encode;      
              return s;      //是的话,返回“GB2312“,以下代码同理
           }      
       } catch (Exception exception) {      
       }      
       encode = "ISO-8859-1";      
      try {      
          if (str.equals(new String(str.getBytes(encode), encode))) {      //判断是不是ISO-8859-1
               String s1 = encode;      
              return s1;      
           }      
       } catch (Exception exception1) {      
       }      
       encode = "UTF-8";      
      try {      
          if (str.equals(new String(str.getBytes(encode), encode))) {   //判断是不是UTF-8
               String s2 = encode;      
              return s2;      
           }      
       } catch (Exception exception2) {      
       }      
       encode = "GBK";      
      try {      
          if (str.equals(new String(str.getBytes(encode), encode))) {      //判断是不是GBK
               String s3 = encode;      
              return s3;      
           }      
       } catch (Exception exception3) {      
       }      
      return "";        //如果都不是,说明输入的内容不属于常见的编码格式。

2017-02-10更新

纠正对”Charset.defaultCharset()“的错误理解,Charset.defaultCharset()“方法的注释内容是返回此Java虚拟机的默认字符集。默认字符集在虚拟机启动期间确定,并且通常取决于底层操作系统的区域设置和字符集。 而字符串的编码是受来源影响的!

但是如”Java同样的汉字在服务器和本地的电脑上URLencode 出来的结果不一致“中提到的,Charset.defaultCharset()“实际上是返回的”file.encoding“,也就是文件采用的编码。

使用”System.getProperties()“ 可以得到如下几种编码相关的属性:

file.encoding.pkg=sun.io

sun.jnu.encoding=GBK

file.encoding=UTF-8

sun.io.unicode.encoding=UnicodeLittle

sun.cpu.endian=little

sun.jnu.encoding 猜测是系统的默认编码,参考:

关于 Java 的系统属性 sun.jnu.encoding 和 file.encoding 的区别
sun.jnu.encoding 影响文件名的创建,而 file.encoding 则影响到文件内容。
所以说,在我们使用 Java 处理中文文件的时候,如果发现文件的中文内容没有乱码,而文件的中文名发生乱码,我们就应当多考虑一下 sun.jnu.encoding 和 file.encoding 的区别了。

file.encoding 处理文件内容默认使用的编码;

使用Eclipse main 方法测试时,会自动根据文件内容的编码确定启动JVM使用的编码,如下图:


如果在这里配置了和文件编码不同的编码方式,文件中的字符串输出可能就会产生乱码,如下面的代码输出为:

ISO-8859-1
?????????? ?????18

	public static void main(String[] args) {
		Properties pro = System.getProperties();
		System.out.println(pro.getProperty("file.encoding"));
		
		try {
			String destination = new String("中文エキサイト네이버 중국어사전17");
			if(destination.equals(new String(destination.getBytes("GB2312"), "GB2312")))
			{
				System.out.println(destination);
			}
			
			destination = new String("中文エキサイト네이버 중국어사전18");
			if(destination.equals(new String(destination.getBytes("utf-8"), "utf-8")))
			{
				System.out.println(destination);
			}
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
由于文件的编码是”UTF-8“,而调试配置的是:ISO-8859-1
上面的代码我们创建一个名为 ”CharsetTest3.java“的文件,在CMD下编译执行:

打开CMD,切换到文件所在目录:

D:\javaProject\javatrans\src\main\java\wasdev\sample\servlet>javac CharsetTest3.
java
CharsetTest3.java:17: 错误: 编码GBK的不可映射字符
                        String destination = new String("涓枃銈ㄣ偔銈点偆銉堧
劋鞚措矂 欷戧淡鞏挫偓鞝?17");

^
CharsetTest3.java:23: 错误: 编码GBK的不可映射字符
                        destination = new String("涓枃銈ㄣ偔銈点偆銉堧劋鞚措矂
 欷戧淡鞏挫偓鞝?18");
                                                                         ^
2 个错误

没有指定编码,与系统默认不符!

D:\javaProject\javatrans\src\main\java\wasdev\sample\servlet>javac CharsetTest3.
java -encoding utf-8
使用”-encoding utf-8“指定编码,执行成功。
注意:在CMD在测试的时候最好不要使用包名,不然很麻烦,我真想说恨死Java了(包的查找方式太恶心,或许是因为性能考虑所以写的这么死板)。

我的文件完整路径是:D:\javaProject\javatrans\src\main\java\wasdev\sample\servlet\CharsetTest3.java

可以通过” -Dfile.encoding=utf-8“指定编码方式


但是CMD应该是使用的GBK编码,不支持韩文,我们把韩文复制粘贴到CMD窗口中发现这一点:


只见光标后移了,却看不见内容。

sun.cpu.endian=little CPU的字节序为小结尾,这涉及到”主机字节序和网络字节序“的问题,通常主机字节序为小结尾(Little endian:将低序字节存储在起始地址),网络字节序为大结尾(Big endian:将高序字节存储在起始地址)。但不同的处理器(CPU)、操作系统也有可能不同。

优化后的方法:

	/**
	 * 判断字符串的编码
	 *
	 * @param str
	 * @return
	 */
	public static String getEncoding(String str) {
		String encode[] = new String[]{
				"UTF-8",
				"ISO-8859-1",
				"GB2312",
				"GBK",
				"GB18030",
				"Big5",
				"Unicode",
				"ASCII"
		};
		for (int i = 0; i < encode.length; i++){
			try {
				if (str.equals(new String(str.getBytes(encode[i]), encode[i]))) {
					return encode[i];
				}
			} catch (Exception ex) {
			}
		}
		
		return "";
	}
说明:把”UTF-8“放在第一位是因为现在使用的比较普遍,见下图:


显示Google记录的2001年至2012年网络上主要编码的使用情况。参考:https://en.wikipedia.org/wiki/UTF-8 测试代码:

	public static void main(String[] args) {
		String str = "中文エキサイト";
		String encode = getEncoding(str);
		System.out.println(encode);
		
		str = "中文エキサイト네이버 중국어사전";
		encode = getEncoding(str);
		System.out.println(encode);
	}
执行输出为: UTF-8
UTF-8
注意:如果将数组”String encode[]“中”UTF-8“和”GB2312“的位置换一下,结果就会发生改变为:
GB2312
UTF-8
这是为什么? 通过监视以下代码中的”destination.getBytes“,我们可以发现是存在重码区域的!

			destination = new String("中文エキサイト네이버 중국어사전17");
			if(destination.equals(new String(destination.getBytes("GB2312"), "GB2312")))
			{
				System.out.println(destination);
			}
			
			destination = new String("中文エキサイト네이버 중국어사전18");
			if(destination.equals(new String(destination.getBytes("utf-8"), "utf-8")))
			{
				System.out.println(destination);
			}

如下图:


所以”getEncoding“方法的正确性有是局限性的,一方面是数组中包含的编码的各类是否够全,一方面是需要判断的字符串特征是否明显。


======================文档信息===========================

版权声明:非商用自由转载-保持署名-注明出处

署名(BY) :testcs_dn(微wx笑)

文章出处:[无知人生,记录点滴](http://blog.csdn.net/testcs_dn)

目录
相关文章
|
10月前
|
IDE Java 编译器
java编程最基础学习
Java入门需掌握:环境搭建、基础语法、面向对象、数组集合与异常处理。通过实践编写简单程序,逐步深入学习,打牢编程基础。
471 1
|
10月前
|
Java
如何在Java中进行多线程编程
Java多线程编程常用方式包括:继承Thread类、实现Runnable接口、Callable接口(可返回结果)及使用线程池。推荐线程池以提升性能,避免频繁创建线程。结合同步与通信机制,可有效管理并发任务。
340 6
|
10月前
|
安全 前端开发 Java
从反射到方法句柄:深入探索Java动态编程的终极解决方案
从反射到方法句柄,Java 动态编程不断演进。方法句柄以强类型、低开销、易优化的特性,解决反射性能差、类型弱、安全性低等问题,结合 `invokedynamic` 成为支撑 Lambda 与动态语言的终极方案。
369 0
|
11月前
|
SQL Java 数据库
2025 年 Java 从零基础小白到编程高手的详细学习路线攻略
2025年Java学习路线涵盖基础语法、面向对象、数据库、JavaWeb、Spring全家桶、分布式、云原生与高并发技术,结合实战项目与源码分析,助力零基础学员系统掌握Java开发技能,从入门到精通,全面提升竞争力,顺利进阶编程高手。
1452 2
|
11月前
|
Java 开发者
Java并发编程:CountDownLatch实战解析
Java并发编程:CountDownLatch实战解析
644 100
|
11月前
|
NoSQL Java 关系型数据库
超全 Java 学习路线,帮你系统掌握编程的超详细 Java 学习路线
本文为超全Java学习路线,涵盖基础语法、面向对象编程、数据结构与算法、多线程、JVM原理、主流框架(如Spring Boot)、数据库(MySQL、Redis)及项目实战等内容,助力从零基础到企业级开发高手的进阶之路。
699 1
|
11月前
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
631 16
|
12月前
|
安全 Java Shell
Java模块化编程(JPMS)简介与实践
本文全面解析Java 9模块化系统(JPMS),帮助开发者解决JAR地狱、类路径冲突等常见问题,提升代码的封装性、性能与可维护性。内容涵盖模块化核心概念、module-info语法、模块声明、实战迁移、多模块项目构建、高级特性及最佳实践,同时提供常见问题和面试高频题解析,助你掌握Java模块化编程精髓,打造更健壮的应用。
|
12月前
|
安全 算法 Java
Java泛型编程:类型安全与擦除机制
Java泛型详解:从基础语法到类型擦除机制,深入解析通配符与PECS原则,探讨运行时类型获取技巧及最佳实践,助你掌握泛型精髓,写出更安全、灵活的代码。
|
12月前
|
安全 Java 数据库连接
2025 年最新 Java 学习路线图含实操指南助你高效入门 Java 编程掌握核心技能
2025年最新Java学习路线图,涵盖基础环境搭建、核心特性(如密封类、虚拟线程)、模块化开发、响应式编程、主流框架(Spring Boot 3、Spring Security 6)、数据库操作(JPA + Hibernate 6)及微服务实战,助你掌握企业级开发技能。
1280 3