Java:IO流之:中文乱码的探究

前言-----

整理是有价值的,记忆无法相信,~

目录

一.理解各种编码规则

二.输出"简"字在4种编码规则下对应的十六进制值

三. 为何会乱码,  如何不乱码

四.从文件读入中文字符时,   如何不乱码

五.写入中文字符到文本时, 如何不乱码

六.如何去掉UTF-8中的BOM标记


一.理解各种编码规则

我的转载博客----"字符串的前世今生"(超链接,请点进去学校), 大家好好看看,先对各种编码规则有所了解,这是重要的基础!!!

二.输出"简"字在4种编码规则下对应的十六进制值

看我上面的文章的话,大家应该知道常用的几种编码规则有:

ANSI:这个不是ASCII的意思而是采用本地编码的意思如果你是中文的操作系统,就会使GBK,如果是英文的就会是ISO-8859-1

Unicode UNICODE原生的编码方式
Unicode big endian 另一个 UNICODE编码方式(大端存储)
UTF-8 最常见的UTF-8编码方式,数字和字母用一个字节, 汉字用3个字节。

demo截图:

结果:

三. 为何会乱码,  如何不乱码

  • 为何为乱码?

根据上面可知: "简"在GBK下对应的编码是bc f2, 在UTF-8下对应的是e7 ae 80

  • 如何不乱码?

  只要把握一个原则: 什么编码规则下的数字,就应该用对应编码去解码出对应的字符 .只要把握出这个规则就不会乱码了

四.从文件读入中文字符时,   如何不乱码

  • 1.首先你要查看文件是用什么编码规则存储的(以记事本为例)

不知道的话,可以自己选择一种类型保存

  • 2.用字节流读取

用字节流读取中文的原理:

用字节流读取出字节数组,再利用String(byte[] ,String CharsetName),将字节数组按照对应的编码规则转化为String

demo1:

测试文件内容:  "简1998"(编码规则:GBK)

	public void testGBK(File f) {
		
		checkFile(f);
		
		//字节流进行读取
		try(FileInputStream fis = new FileInputStream(f)){
			
			byte []myByte =new byte[(int)f.length()];
			
			fis.read(myByte);
			String str = new String(myByte, "GBK");
			System.out.println(str);
			
		}catch(Exception e) {
			
			e.printStackTrace();
		}
}

结果:

demo2:

测试文件内容:  "简1998"(编码规则:UTF-8)

	public void testUTF8(File f) {
	   
		checkFile(f);
		
		//用字节流读取
		try(FileInputStream fis = new FileInputStream(f)){
			
			byte []myByte = new byte[(int)f.length()];
			
			fis.read(myByte);
			
			
		   String str = new String(myByte,"UTF8");//用UTF8去识别对应的字节数组,转化为对应的字符
		   System.out.println(str);
			
			
			
		}catch(Exception e) {
			e.printStackTrace();
		}
}

结果:

demo3:

测试文件内容:  "简1998"(编码规则:Unicode)

	public void testUnicode(File f) {
		
	  checkFile(f);
	  
	  //用字节流进行读取
	  try(FileInputStream fis = new FileInputStream(f)){
		  
		  byte []myByte =new byte[(int)f.length()];
		  
		  fis.read(myByte);
		  String str = new String(myByte,"Unicode");
		  System.out.println(str);
		  
	  }catch(Exception e) {
		  
		  e.printStackTrace();
	  }
}

结果:

  • 3.用字符流读取

用字符流读取时, 其实内部有用到缓冲区(内存中),然后直接传字节数组给程序,程序再用对应的编码规则去解码它,但是此时这个编码规则取决于谁呢? 

其实取决于FileReader,  而FileReader使用的编码方式是Charset.defaultCharset()的返回值,如果是中文的操作系统,就是GBK.
FileReader是不能手动设置编码方式的,为了使用其他的编码方式,只能使用InputStreamReader来代替,像这样:

new InputStreamReader(new InputStream(File f) ,Charset.forName("Unicode"), 这样我们就可以指定对应的解码规则了

demo 1:

测试文件内容:  "简1998"(编码规则:GBK)

	public void testGBK(File f) {
		
		checkFile(f);
        try(InputStreamReader isr = new InputStreamReader(new FileInputStream(f), Charset.forName("GBK"))){
			
		char [] myChar = new char[(int)f.length()];
		isr.read(myChar);
			
		System.out.println(myChar);
			
		}catch(Exception e) {
			e.printStackTrace();
		}
		
		
	}

结果:

demo2

测试文件内容:  "简1998"(编码规则:UTF-8)

	public void testUTF8(File f) {
	   
		checkFile(f);
		try( InputStreamReader isr = new InputStreamReader( new FileInputStream(f), Charset.forName("UTF-8") ) ){
			
			 //虽然返回的是字节长度,但是如果一个字符是多个字节的话,字符数一定是小于字节数的,所以长度肯定是可以够读的
		   char [] myChar = new char[(int)f.length()];  
		   isr.read(myChar);
		   
		   System.out.println(myChar);
		   
			
		}catch(Exception e) {
			
			e.printStackTrace();
		}
	
		
	
	}

测试结果:

demo3:

测试文件内容:  "简1998"(编码规则:Unicode)

public void testUnicode(File f) {
		
	  checkFile(f);
      try(  InputStreamReader isr =new InputStreamReader(new FileInputStream(f),Charset.forName("Unicode")) ){
		  
	  char [] myChar =new char[(int)f.length()];
		  
	  isr.read(myChar);
	  System.out.println(myChar);
		  
	  }catch(Exception e) {
		  e.printStackTrace();
	  }
	  
	  

   }

测试结果:

五.写入中文字符到文本时, 如何不乱码

首先我们要知道被写入的文本是用什么编码机制,就像上面所说的那样....然后我们用String的getBytes(byte[], String CharsetName ), 将要输入的字符串转化为对应编码下的字节数组,然后再写入.

1.用字节流写入(FIleOutputStream)

demo1: 

测试文件:内容为空(用GBK保存)

   public void testOutputGBK(File f) {
	   
	   checkFile(f);
	   //用字节流写到文件
	   String str = "简1998";
	   
	   try(  FileOutputStream fos = new FileOutputStream(f)  ){
		   
		   byte [] myByte = str.getBytes("GBK");
		   
		   fos.write(myByte);
		   
	   }catch(Exception e) {
		   e.printStackTrace();
	   }
   }

测试结果:

demo2:

测试文件:内容为空(用UTF-8保存)

   public void testOutputUTF8(File f) {
	   
	   checkFile(f);
	   String str = "简1998";
	   try(FileOutputStream fos = new FileOutputStream(f)){
		   
		   byte [] myByte = str.getBytes("UTF-8");
		   
		   fos.write(myByte);
		   
	   }catch(Exception e) {
		   
		  e.printStackTrace();
	   }
   }

测试结果:

demo3

测试文件:内容为空(用Unicode保存)

   public void testOutputUnicode(File f) {
	   
	   checkFile(f);
	   
	   String str = "简1998";
	   
	   try(FileOutputStream fos = new FileOutputStream(f)){
		   
		   byte[] myByte = str.getBytes("Unicode");
		   fos.write(myByte);
	   }catch(Exception e) {
		   e.printStackTrace();
	   }
   }

测试结果:

2.用字符流写入(FIleOutputStream)

跟用字符流读一样, 如果用FIleWriter去写的话,那么FileWriter只会用Charset.defaultCharset()的返回值(中文操作系统下默认是GBK)去解码字符, 然后写入缓冲区,接着再从缓冲区把字节写入文件中, 我们必须要用OutputStreamWriter去写入, 像这样

new OutputStreamWriter( new FIleOutputStream(f), Charset.forName("UTF-8")) 这样, 原因在于我们能改变解码方式

demo1:

测试文件:内容为空(用GBK保存)

   public void testOutputGBK(File f) {
	   
	   checkFile(f);

	   
	   //用字符流写到文件
	   
	   String str = "简1998";
	   
	   try(OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(f), Charset.forName("GBK"))){
		   
		   
		   osw.write(str);
	   }catch(Exception e) {
		   e.printStackTrace();
	   }
   }

测试结果:

demo2:

测试文件:内容为空(用UTF-8保存)

   public void testOutputUTF8(File f) {
	   
	   checkFile(f);
	   String str = "简1998";

	   
	   try( OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(f),Charset.forName("UTF-8"))){
		   
		   osw.write(str);
	   }catch(Exception e) {
		   e.printStackTrace();
	   }
   }

测试结果:

demo3:

测试文件:内容为空(用Unicode保存)

   public void testOutputUnicode(File f) {
	   
	   checkFile(f);
	   
	   String str = "简1998";

	   
	   try(OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(f),Charset.forName("Unicode"))){
		   
		   osw.write(str);
	   }catch(Exception e) {
		   e.printStackTrace();
	   }
   }

测试结果:

六.如何去掉UTF-8中的BOM标记

大家应该会发现,从UTF-8格式的文件读入中文时,会出现 ?   为什么"简"字前面有一个?
如果是使用记事本另存为UTF-8的格式,那么在第一个字节有一个标示符,叫做BOM用来标志这个文件是用UTF-8来编码的。

BOM对应的十六进制是: ee bb bf,    那么我们如何把读入的BOM给去除呢?

demo:

测试文件:简1998(UTF-8保存)

public void removeBOM(File f){

		checkFile(f);
		
		
		//用字节流读取
		try(FileInputStream fis = new FileInputStream(f)){
			
			byte []myByte = new byte[(int)f.length()];
			
			fis.read(myByte);
			
			for(byte i : myByte) {
				
				int k = i&0xff;
				System.out.println(Integer.toHexString(k));
			}
			
			System.out.println("我们发现了BOM标致对应的16进制是ee ,ef,bf");
			byte [] removeBOM = new byte[myByte.length];
			
			for(int i= 0 ;i < myByte.length ;i++) {
				
				if(i==0 || i==1 || i==2)
					continue;
				removeBOM[i -3] = myByte[i];
			}
			
		   System.out.println("我们将取出BOM的removeBOM进行转换,就不会出现中文字符了");
		   String str = new String(removeBOM,"UTF8");//用UTF8去识别对应的字节数组,转化为对应的字符
		   System.out.println(str);
			
			
			
		}catch(Exception e) {
			e.printStackTrace();
                 }
}
		

测试结果:

猜你喜欢

转载自blog.csdn.net/CCSGTC/article/details/84195917
今日推荐