说到乱码,相信很多初学程序的小白们都遇见过,并且也并不知道如何去解决这个问题,今天就给大家分享一下有关乱码的解决方法,在这之前,我觉得有必要先来聊一下编码的知识。
java技术学习qun:59,789,1510,每天分享一点java知识干货!String(byte[] bytes, String charsetName):通过指定的字符集解码字节数组
byte[] getBytes(String charsetName):使用指定的字符集合把字符串编码为字节数组
编码:把看得懂的变成看不懂的
String -- byte[]
解码:把看不懂的变成看得懂的
byte[] -- String
因此字节流读取的数据是编码过的数据,我们解码就行了。
编码问题简单,只要编码解码的格式是一致的。
计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字。就将各个国家的文字用数字来表示,并一一对应,形成一张表。
ASCII:美国标准信息交换码。
用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表
用一个字节的8位表示。
GB2312:中国的中文编码表。
GBK:中国的中文编码表升级,融合了更多的中文文字符号。
GB18030:GBK的取代版本
BIG-5码 :通行于台湾、香港地区的一个繁体字编码方案,俗称“大五码”。
Unicode:国际标准码,融合了多种文字。
所有文字都用两个字节来表示,Java语言使用的就是unicode
UTF-8:最多用三个字节来表示一个字符。
UTF-8不同,它定义了一种“区间规则”,这种规则可以和ASCII编码保持最大程度的兼容:
它将Unicode编码为00000000-0000007F的字符,用单个字节来表示�
它将Unicode编码为00000080-000007FF的字符用两个字节表示
它将Unicode编码为00000800-0000FFFF的字符用3字节表示
示例:
String s = "你好";
byte[] bytes1 = s.getBytes();
System.out.println(Arrays.toString(bytes1));//[-28, -67, -96, -27, -91, -67] 默认编码utf-8
byte[] bytes2 = s.getBytes("GBK");
System.out.println(Arrays.toString(bytes2));//[-60, -29, -70, -61]
byte[] bytes3 = s.getBytes("UTF-8");
System.out.println(Arrays.toString(bytes3));//[-28, -67, -96, -27, -91, -67]
String s1 = new String(bytes1);
System.out.println(s1);//你好
String s2 = new String(bytes2,"GBK");
System.out.println(s2);//你好
String s3 = new String(bytes2,"gbk");
System.out.println(s3);//你好
String s4 = new String(bytes3);
System.out.println(s4);//你好
String s5 = new String(bytes3,"gbk");
System.out.println(s5);//浣犲ソ
虽然字节流有解决乱码的方案,但并不方便,所以java io流就设计出了转换流,一场乱码引发的变革。
(OutputStreamWriter、InputStreamReader)
OutputStreamWriter(OutputStream out):根据默认编码把字节流的数据转换为字符流
OutputStreamWriter(OutputStream out,String charsetName):根据指定编码把字节流数据转换为字符流
java技术学习qun:59,789,1510,每天分享一点java知识干货!乱码导火索:
在io流里,先诞生了字节流,但是字节流读取数据会有乱码的问题(读中文会乱码)。比如:
FileInputStream fis = new FileInputStream("a.txt");
// int by = 0;
// while ((by=fis.read() )!= -1) {
// System.out.print((char)by);//bcdbcdbcdbcdbcdbcdhello ä¸å�½
// //因为还正常,中文就乱码了,有什么办法解决吗,有,就是有点麻烦
// }
从文件中读取中文会有乱码,当然字节流有解决措施。
FileInputStream fis = new FileInputStream("a.txt");
byte[] bytes = new byte[1024];
int len = 0;
while ((len = fis.read(bytes)) != -1) {
System.out.println(new String(bytes,0,len));//bcdbcdbcdbcdbcdbcdhello 中国
//查看new String()的源码,this.value = StringCoding.decode(bytes, offset, length);
//点进decode,循序渐进发现,默认编码是UTF-8
//通过源码,也看到了这个方法public String(byte bytes[], int offset, int length, String charsetName)
}
但是解码这并不是字节流做的,而是String的功能。查看String的源码,构造方法有解码功能,并且默认编码是utf-8。
把字节流转换为字符流。
//创造对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"));//查看源码,java8 默认utf-8
//写数据
osw.write("中国");
//释放资源
osw.close();//close包含了close和flush的作用
一般默认编码就够了。
java技术学习qun:59,789,1510,每天分享一点java知识干货!查看源码,发现OutputStreamWriter有5个write方法。
/*
* OutputStreamWriter的方法:
* public void write(int c):写一个字符
* public void write(char[] cbuf):写一个字符数组
* public void write(char[] cbuf,int off,int len):写一个字符数组的一部分
* public void write(String str):写一个字符串
* public void write(String str,int off,int len):写一个字符串的一部分
*
* 面试题:close()和flush()的区别?
* A:close()关闭流对象,但是先刷新一次缓冲区。关闭之后,流对象不可以继续再使用了。
* B:flush()仅仅刷新缓冲区,刷新之后,流对象还可以继续使用。
*/
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("c.txt"));//查看源码,java8 默认utf-8
//写一个字符
osw.write('a');
osw.write(97);
osw.write('中');
// 为什么数据没有进去呢?
// 原因是:字符 = 2字节
// 文件中数据存储的基本单位是字节。
// void flush()
osw.flush();
//写一个字符数组
char[] chars = {'a','b','中','国'};
osw.write(chars);
osw.flush();
//写一个字符数组的一部分
osw.write(chars,2,2);
osw.flush();
//写一个字符串
osw.write("中国");
//写一个字符串的一部分
osw.write("中国你好",2,2);
osw.close();
InputStreamReader(InputStream is):用默认的编码读取数据,默认utf-8
InputStreamReader(InputStream is,String charsetName):
java技术学习qun:59,789,1510,每天分享一点java知识干货!用指定的编码读取数据
//创建对象
InputStreamReader isr = new InputStreamReader(new FileInputStream("b.txt"));//默认编码utf-8
InputStreamReader isr1 = new InputStreamReader(new FileInputStream("b.txt"),"gbk");//可指定编码
//读数据
int ch = 0;
while ((ch = isr.read()) != -1) {
System.out.print((char)ch);//中国
}
//释放资源
isr.close();
//只有文档的编码和读取的编码一致才不会乱码。
查看源码知道InputStreamReader有2个read方法。
/*
* InputStreamReader的方法:
* int read():一次读取一个字符
* int read(char[] chs):一次读取一个字符数组
*/
InputStreamReader isr = new InputStreamReader(new FileInputStream("c.txt"));
//读一个字符
// int ch = 0;
// while ((ch = isr.read()) != -1) {
// System.out.print((char) ch);//9797200139798200132226920013222691020013222692032022909/
// //aa中ab中国中国
// //中国你好
// }
//isr.close();
//读一个字符数组
char[] chars =new char[1024];
int len = 0;
while ((len = isr.read(chars)) != -1) {
System.out.println(chars.length);//1024
System.out.println(new String(chars,0,len));
//aa中ab中国中国
//中国你好
}
isr.close();
现在我们可以通过转换流升级字节流复制文件的方式了。
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("e:\a.txt"));
char [] chars = new char[1024];
int len = 0 ;
while ((len = isr.read(chars)) != -1) {
osw.write(chars,0,len);
osw.flush();
}
osw.close();
isr.close();
好了,本篇文章就分享到这里了。有兴趣的新手伙伴们可以关注收藏起来,以后需要的时候可以多看看。如果有正在学java的程序员,可来我们的java技术学习扣qun哦:59789,1510里面免费送java的视频系统教程!
网友评论