java基础io流之乱码的解决办法

说到乱码,相信很多初学程序的小白们都遇见过,并且也并不知道如何去解决这个问题,今天就给大家分享一下有关乱码的解决方法,在这之前,我觉得有必要先来聊一下编码的知识。

java基础io流之乱码的解决办法

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基础io流之乱码的解决办法

乱码导火索:

在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基础io流之乱码的解决办法

查看源码,发现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基础io流之乱码的解决办法

用指定的编码读取数据

//创建对象
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的视频系统教程!

猜你喜欢

转载自blog.csdn.net/weixin_43660525/article/details/86521882