本视频是解读性视频,所以希望您已经看过了本知识点的内容,并且编写了相应的代码之后,带着疑问来观看,这样收获才多。 不建议一开始就观看视频
42分55秒 本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器。 如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)。 chrome 的 视频下载插件会影响播放,如 IDM 等,请关闭或者切换其他浏览器 步骤 1 : 编码概念 步骤 2 : 常见编码 步骤 3 : UNICODE和UTF 步骤 4 : Java采用的是Unicode 步骤 5 : 一个汉字使用不同编码方式的表现 步骤 6 : 文件的编码方式-记事本 步骤 7 : 文件的编码方式-eclipse 步骤 8 : 用FileInputStream 字节流正确读取中文 步骤 9 : 用FileReader 字符流正确读取中文 步骤 10 : 练习-数字对应的中文 步骤 11 : 答案-数字对应的中文 步骤 12 : 练习-移除BOM 步骤 13 : 答案-移除BOM
计算机存放数据只能存放数字,所有的字符都会被转换为不同的数字。
就像一个棋盘一样,不同的字,处于不同的位置,而不同的位置,有不同的数字编号。 有的棋盘很小,只能放数字和英文 有的大一点,还能放中文 有的“足够”大,能够放下世界人民所使用的所有文字和符号 如图所示,英文字符 A 能够放在所有的棋盘里,而且位置都差不多 中文字符, 中文字符 中 能够放在后两种棋盘里,并且位置不一样,而且在小的那个棋盘里,就放不下中文
工作后经常接触的编码方式有如下几种:
ISO-8859-1 ASCII 数字和西欧字母 GBK GB2312 BIG5 中文 UNICODE (统一码,万国码) 其中 ISO-8859-1 包含 ASCII GB2312 是简体中文,BIG5是繁体中文,GBK同时包含简体和繁体以及日文。 UNICODE 包括了所有的文字,无论中文,英文,藏文,法文,世界所有的文字都包含其中
根据前面的学习,我们了解到不同的编码方式对应不同的棋盘,而UNICODE因为要存放所有的数据,那么它的棋盘是最大的。
不仅如此,棋盘里每个数字都是很长的(4个字节),因为不仅要表示字母,还要表示汉字等。 如果完全按照UNICODE的方式来存储数据,就会有很大的浪费。 比如在ISO-8859-1中,a 字符对应的数字是0x61 而UNICODE中对应的数字是 0x00000061,倘若一篇文章大部分都是英文字母,那么按照UNICODE的方式进行数据保存就会消耗很多空间 在这种情况下,就出现了UNICODE的各种减肥子编码, 比如UTF-8对数字和字母就使用一个字节,而对汉字就使用3个字节,从而达到了减肥还能保证健康的效果 UTF-8,UTF-16和UTF-32 针对不同类型的数据有不同的减肥效果,一般说来UTF-8是比较常用的方式 UTF-8,UTF-16和UTF-32 彼此的区别在此不作赘述,有兴趣的可以参考 unicode-百度百科
写在.java源代码中的汉字,在执行之后,都会变成JVM中的字符。
而这些中文字符采用的编码方式,都是使用UNICODE. "中"字对应的UNICODE是4E2D,所以在内存中,实际保存的数据就是十六进制的0x4E2D, 也就是十进制的20013。 package stream;
public class TestStream {
public static void main(String[] args) {
String str = "中";
}
}
package stream; public class TestStream { public static void main(String[] args) { String str = "中"; } }
以字符 中 为例,查看其在不同编码方式下的值是多少
也即在不同的棋盘上的位置 package stream;
import java.io.UnsupportedEncodingException;
public class TestStream {
public static void main(String[] args) {
String str = "中";
showCode(str);
}
private static void showCode(String str) {
String[] encodes = { "BIG5", "GBK", "GB2312", "UTF-8", "UTF-16", "UTF-32" };
for (String encode : encodes) {
showCode(str, encode);
}
}
private static void showCode(String str, String encode) {
try {
System.out.printf("字符: \"%s\" 的在编码方式%s下的十六进制值是%n", str, encode);
byte[] bs = str.getBytes(encode);
for (byte b : bs) {
int i = b&0xff;
System.out.print(Integer.toHexString(i) + "\t");
}
System.out.println();
System.out.println();
} catch (UnsupportedEncodingException e) {
System.out.printf("UnsupportedEncodingException: %s编码方式无法解析字符%s\n", encode, str);
}
}
}
接下来讲,字符在文件中的保存
字符保存在文件中肯定也是以数字形式保存的,即对应在不同的棋盘上的不同的数字 用记事本打开任意文本文件,并且另存为,就能够在编码这里看到一个下拉。 ANSI 这个不是ASCII的意思,而是采用本地编码的意思。如果你是中文的操作系统,就会使GBK,如果是英文的就会是ISO-8859-1 Unicode UNICODE原生的编码方式 Unicode big endian 另一个 UNICODE编码方式 UTF-8 最常见的UTF-8编码方式,数字和字母用一个字节, 汉字用3个字节。
eclipse也有类似的编码方式,右键任意文本文件,点击最下面的"property"
就可以看到Text file encoding 也有ISO-8859-1,GBK,UTF-8等等选项。 其他的US-ASCII,UTF-16,UTF-16BE,UTF-16LE不常用。
为了能够正确的读取中文内容
1. 必须了解文本是以哪种编码方式保存字符的 2. 使用字节流读取了文本后,再使用对应的编码方式去识别这些数字,得到正确的字符 如本例,一个文件中的内容是字符中,编码方式是GBK,那么读出来的数据一定是D6D0。 再使用GBK编码方式识别D6D0,就能正确的得到字符中 注: 在GBK的棋盘上找到的中字后,JVM会自动找到中在UNICODE这个棋盘上对应的数字,并且以UNICODE上的数字保存在内存中。 package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class TestStream {
public static void main(String[] args) {
File f = new File("E:\\project\\j2se\\src\\test.txt");
try (FileInputStream fis = new FileInputStream(f);) {
byte[] all = new byte[(int) f.length()];
fis.read(all);
//文件中读出来的数据是
System.out.println("文件中读出来的数据是:");
for (byte b : all)
{
int i = b&0x000000ff; //只取16进制的后两位
System.out.println(Integer.toHexString(i));
}
System.out.println("把这个数字,放在GBK的棋盘上去:");
String str = new String(all,"GBK");
System.out.println(str);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
FileReader得到的是字符,所以一定是已经把字节根据某种编码识别成了字符了
而FileReader使用的编码方式是Charset.defaultCharset()的返回值,如果是中文的操作系统,就是GBK FileReader是不能手动设置编码方式的,为了使用其他的编码方式,只能使用InputStreamReader来代替,像这样: new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8")); 在本例中,用记事本另存为UTF-8格式,然后用UTF-8就能识别对应的中文了。 解释: 为什么中字前面有一个? 如果是使用记事本另存为UTF-8的格式,那么在第一个字节有一个标示符,叫做BOM用来标志这个文件是用UTF-8来编码的。 package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
public class TestStream {
public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException {
File f = new File("E:\\project\\j2se\\src\\test.txt");
System.out.println("默认编码方式:"+Charset.defaultCharset());
//FileReader得到的是字符,所以一定是已经把字节根据某种编码识别成了字符了
//而FileReader使用的编码方式是Charset.defaultCharset()的返回值,如果是中文的操作系统,就是GBK
try (FileReader fr = new FileReader(f)) {
char[] cs = new char[(int) f.length()];
fr.read(cs);
System.out.printf("FileReader会使用默认的编码方式%s,识别出来的字符是:%n",Charset.defaultCharset());
System.out.println(new String(cs));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//FileReader是不能手动设置编码方式的,为了使用其他的编码方式,只能使用InputStreamReader来代替
//并且使用new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8")); 这样的形式
try (InputStreamReader isr = new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8"))) {
char[] cs = new char[(int) f.length()];
isr.read(cs);
System.out.printf("InputStreamReader 指定编码方式UTF-8,识别出来的字符是:%n");
System.out.println(new String(cs));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
找出 E5 B1 8C 这3个十六进制对应UTF-8编码的汉字
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
本视频是解读性视频,所以希望您已经看过了本答案的内容,带着疑问来观看,这样收获才多。 不建议一开始就观看视频
1分10秒 本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器。 如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)。 chrome 的 视频下载插件会影响播放,如 IDM 等,请关闭或者切换其他浏览器 package stream;
import java.io.UnsupportedEncodingException;
public class TestStream {
public static void main(String[] args) throws UnsupportedEncodingException {
// 找出 E5 B1 8C 这3个十六进制对应UTF-8编码的汉字
byte[] bs = new byte[3];
bs[0] = (byte) 0xE5;
bs[1] = (byte) 0xB1;
bs[2] = (byte) 0x8C;
String str =new String(bs,"UTF-8");
System.out.println("E5 B1 8C 对应的字符是:"+str);
}
}
package stream; import java.io.UnsupportedEncodingException; public class TestStream { public static void main(String[] args) throws UnsupportedEncodingException { // 找出 E5 B1 8C 这3个十六进制对应UTF-8编码的汉字 byte[] bs = new byte[3]; bs[0] = (byte) 0xE5; bs[1] = (byte) 0xB1; bs[2] = (byte) 0x8C; String str =new String(bs,"UTF-8"); System.out.println("E5 B1 8C 对应的字符是:"+str); } }
如果用记事本根据UTF-8编码保存汉字就会在最前面生成一段标示符,这个标示符用于表示该文件是使用UTF-8编码的。
找出这段标示符对应的十六进制,并且开发一个方法,自动去除这段标示符
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
本视频是解读性视频,所以希望您已经看过了本答案的内容,带着疑问来观看,这样收获才多。 不建议一开始就观看视频
8分57秒 本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器。 如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)。 chrome 的 视频下载插件会影响播放,如 IDM 等,请关闭或者切换其他浏览器 package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
public class TestStream {
public static void main(String[] args) {
File f = new File("E:\\project\\j2se\\src\\test.txt");
try (FileInputStream fis = new FileInputStream(f);) {
byte[] all = new byte[(int) f.length()];
fis.read(all);
System.out.println("首先确认按照UTF-8识别出来有?");
String str = new String(all,"UTF-8");
System.out.println(str);
System.out.println("根据前面的所学,知道'中'字对应的UTF-8编码是:e4 b8 ad");
System.out.println("打印出文件里所有的数据的16进制是:");
for (byte b : all) {
int i = b&0xff;
System.out.print(Integer.toHexString(i)+ " ");
}
System.out.println();
System.out.println("通过观察法得出 UTF-8的 BOM 是 ef bb bf");
byte[] bom = new byte[3];
bom[0] = (byte) 0xef;
bom[1] = (byte) 0xbb;
bom[2] = (byte) 0xbf;
byte[] fileContentWithoutBOM= removeBom(all,bom);
System.out.println("去掉了BOM之后的数据的16进制是:");
for (byte b : fileContentWithoutBOM) {
int i = b&0xff;
System.out.print(Integer.toHexString(i)+ " ");
}
System.out.println();
System.out.println("对应的字符串就没有问号了:");
String strWithoutBOM=new String(fileContentWithoutBOM,"UTF-8");
System.out.println(strWithoutBOM);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static byte[] removeBom(byte[] all, byte[] bom) {
return Arrays.copyOfRange(all, bom.length, all.length);
}
}
HOW2J公众号,关注后实时获知最新的教程和优惠活动,谢谢。
问答区域
2024-07-06
纠正UTF-8编码出现的标识符和冗余的空白符
1 个答案
13457882007 跳转到问题位置 答案时间:2024-09-15 对,吗的,搞半天,发现可以自己选择utf-8或者utf-8 BOM,不选utf-8 bom编码保存压根不会有那个标志
回答已经提交成功,正在审核。 请于 我的回答 处查看回答记录,谢谢
2021-10-25
为什么中文后面会有多余的字符?
2021-06-06
练习-移除BOM
2021-06-06
练习-数字对应的中文
提问太多,页面渲染太慢,为了加快渲染速度,本页最多只显示几条提问。还有 62 条以前的提问,请 点击查看
提问之前请登陆
提问已经提交成功,正在审核。 请于 我的提问 处查看提问记录,谢谢
|