字符串的序列化(文字的编码方案)
从char序列到byte序列 的转换,叫"编码"
1) String 字符串本质上是Char
2)utf-16be 编码-----将16位char从中间切开为2个byte
utf -16be是将 unicode char[] 序列化为byte[]的编码方案
能够支持65535个字符编码,英文浪费空间
如:
char[] = ['A', 'B', '中']
对应 0041,0042,4e2d
utf-8:国际标准,是将unicode编码为byte序列的方案,采用变长编码 1-N方案,其中英文1个byte,中文3个byte
unicoded的" 中": 4e 2d = 01001110 00101101
utf-8的"中":e4 b8 ad =11100100 10111000 10101101
1110xxxx 10xxxxxx 10xxxxxx
以0开头的是英文(0-127)
110表示连续2字节表示一个字符
1110表示连续3字节表示一个字符
每个数据字节以10开头
GBK: 中国标准,支持20000+中日韩文,英文编码1byte,中文2byte
与unicode不兼容,中文windows默认gbk
ISO8859-1:只支持255个英文字符,不支持中文(Sun服务器默认编码,如tomcat等)
例子
1 import java.io.FileOutputStream; 2 import java.io.IOException; 3 import java.io.OutputStream; 4 5 public class CharIODemo { 6 public static void main(String[] args) 7 throws IOException{ 8 String str = "ABCD中国"; 9 System.out.println(str); 10 //Java 的字符是16位 Unicode值,而文件是8位Byte序列 11 12 //GBK 13 System.out.println("GBK编码方案,对字符编码"); 14 String file = "gbk.txt"; 15 OutputStream out = new FileOutputStream(file);//默认GBK编码方案 16 byte[] gbk = str.getBytes("GBK"); 17 out.write(gbk); 18 out.close(); 19 IOUtils.print(file); 20 //UTF-16BE,每个编码是2个字节 21 System.out.println("UTF-16BE编码方案,对字符编码"); 22 file = "utf-16be.txt"; 23 out = new FileOutputStream(file); 24 byte[] utf16be = str.getBytes("UTF-16BE"); 25 out.write(utf16be); 26 out.close(); 27 IOUtils.print(file); 28 29 //UTF-8,英文是1个字节,中文是3个字节 30 System.out.println("UTF-8编码方案,对字符编码"); 31 file = "utf-8.txt"; 32 out = new FileOutputStream(file); 33 byte[] utf8 = str.getBytes("UTF-8");//编码string -> byte[] 34 out.write(utf8); 35 out.close(); 36 IOUtils.print(file); 37 38 byte[] buf = IOUtils.read("utf-8.txt"); 39 //new String(buf,"UTF-8"),构造器可以将 byte编码序列 40 //解码为 char序列(字符串) 41 String s = new String(buf,"UTF-8");//解码byte-> String 42 System.out.println(s); 43 } 44 }
6 字符流IO(Reader Writer)
1) 字符的处理,一次处理一个字符(unicode编码)
2) 字符的底层仍然是基本的字节流
3) 字符流的基本实现
InputStreamReader 完成byte流解析为char流,按照编码解析
OutputStreamWriter 提供char流到byte流,按照编码处理
4) 字符流的过滤器
是字符读写的功能扩展,极大的方便了文本的读写操作
BufferedReader : readLine() 一次读取一行
PrintWriter : println() 一次打印一行
5)读取一个文本文件
InputStream is = new FileInputStream("test.txt");
Reader in = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(in);
或者
BufferedReader in = new BufferedReader(new FileReader(filename));
例子:
1 import java.io.BufferedInputStream; 2 import java.io.BufferedReader; 3 import java.io.FileInputStream; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 7 public class TestReaderDemo { 8 public static void main(String[] args) 9 throws IOException{ 10 //Scanner BufferedReader都是流的功能扩展,是过滤器 11 // 不能单独使用,最终需要依赖于基本byte流(in) 12 //Scanner 提供了nextLine()方法//Java5以后 13 //BufferedReader 提供了 readLine()方法,读取一行 14 //readLine()读取到文件末尾返回null 15 16 //逐行读取文本文件,显示到系统控制台 17 //工作中常用 18 String file = "in.txt"; //为当前工作区workspace/项目名/in.txt 19 BufferedReader in = new BufferedReader( 20 new InputStreamReader( 21 new BufferedInputStream( 22 new FileInputStream(file)),"gbk")); 23 String str; 24 while((str = in.readLine()) != null){ 25 System.out.println(str); 26 } 27 in.close(); 28 }
6)写出一个文本文件
PrintWriter out = new PrintWriter(new FileWriter(new FileOutputStream(filename)));
或者
PrintWriter out = new PrintWriter(
new OutputStreamWriter(
new FileOutputStream(filename)))
例子
1 import java.io.IOException; 2 import java.io.PrintWriter; 3 import java.util.Scanner; 4 5 public class SyncWriteDemo { 6 public static void main(String[] args) 7 throws IOException{ 8 Scanner in = new Scanner(System.in); 9 String file = "sync.txt"; 10 PrintWriter out = new PrintWriter(file,"UTF-8"); 11 while(true){ 12 String str = in.nextLine(); 13 out.println(str); 14 if("q".equalsIgnoreCase(str)){ 15 break; 16 } 17 } 18 out.close(); 19 } 20 }
7)系统的默认编码,中文一般是GBK
如何查看默认编码?
String encoding = System.getProperty("file.encoding");
7 对象的IO序列化和深层复制
什么是对象序列化:
将对象Object转换为byte序列,反之叫做对象的反序列华
1)序列化流,是过滤流
ObjectOutputStream 方法 writeObject() 对象的序列化
ObjectInputStream 方法readObject() 对象的反序列化
2)序列化接口(Serializable)
对象必须实现"序列化接口Serializable"才能进行序列化,否则将出现不能序列化的异常
Serializable是一个空的接口,没有任何方法 ,仅作为序列化的一个标识
3)JavaBean 规范规定,Java类必须实现Serializable接口
Java API中的类大多是符合Java Bean规范的,基本都实现了Serializable
4) 对象的序列化可以变相实现对象的深层复制
例子
1 import java.io.BufferedInputStream; 2 import java.io.BufferedOutputStream; 3 import java.io.FileInputStream; 4 import java.io.FileOutputStream; 5 import java.io.ObjectInputStream; 6 import java.io.ObjectOutputStream; 7 import java.io.Serializable; 8 9 public class ObjectIODemo { 10 public static void main(String[] args) 11 throws Exception{ 12 String file = "obj.dat"; 13 ObjectOutputStream out = new ObjectOutputStream( 14 new BufferedOutputStream( 15 new FileOutputStream(file))); 16 Foo foo =new Foo(); 17 out.writeObject(foo);//将foo引用的对象,序列化到文件中 18 out.close(); 19 20 //读出 21 ObjectInputStream in = new ObjectInputStream( 22 new BufferedInputStream( 23 new FileInputStream(file))); 24 Foo foo1 = (Foo)in.readObject();//对象反序列化 25 in.close(); 26 System.out.println(foo1.name); 27 28 System.out.println("深层复制:对象被复制,对象属性也被复制"); 29 System.out.println(foo==foo1);//false 对象复制了(一层) 30 System.out.println(foo.name == foo1.name);//false ,属性被复制了(二层) 31 //利用序列化 和 反序列化 可以简洁的实现 对象的深层复制 32 } 33 34 } 35 class Foo implements Serializable{//Serializable没有声明方法 36 String name = "Tom"; 37 }
浅层复制与深层复制
1)java的默认规则是浅层复制,性能好,但隔离性差,如(clone(),Arrays.copyOf)
浅层复制 : 对象的引用不同,但对象中属性的引用相同
2)利用序列化可以实现深层复制
深层复制: 对象的引用不同,但对象中的属性的引用也不相同
例
1 import java.io.ByteArrayInputStream; 2 import java.io.ByteArrayOutputStream; 3 import java.io.ObjectInputStream; 4 import java.io.ObjectOutputStream; 5 6 public class DeepcopyDemo { 7 public static Object deepCope(Object obj){ 8 try{ 9 //1. 对象序列化 10 // 缓冲流: 字节数组输出流 11 ByteArrayOutputStream buf = 12 new ByteArrayOutputStream(); 13 //对象输出流 14 ObjectOutputStream out = 15 new ObjectOutputStream( 16 new ByteArrayOutputStream()); 17 18 out.writeObject(obj);//序列化对象到buf中 19 out.close(); 20 21 //2 .对象的反序列化 22 byte[] ary = buf.toByteArray(); 23 ByteArrayInputStream bais = 24 new ByteArrayInputStream(ary); 25 ObjectInputStream in = 26 new ObjectInputStream(bais); 27 Object o = in.readObject();//从ary反序列化 28 in.close(); 29 return o; 30 31 }catch(Exception e){ 32 e.printStackTrace(); 33 throw new RuntimeException(e); 34 } 35 } 36 }
以上用到的ByteArrayInputStream和ByteArrayOutputStream
下面有一个ByteArrayInputStream和ByteArrayOutputStream的例子
例子
1 import java.io.ByteArrayInputStream; 2 import java.io.ByteArrayOutputStream; 3 import java.io.IOException; 4 import java.util.Arrays; 5 6 import com.tarena.day18.IOUtils; 7 8 public class ByteArrayIODemo { 9 public static void main(String[] args) 10 throws IOException{ 11 byte[] ary = {1,-1,127,-128}; 12 // {00000001, 11111111, 01111111, 10000000} 13 ByteArrayInputStream in = new ByteArrayInputStream(ary); 14 int b = in.read();//1 00000000 00000000 00000000 00000001 15 System.out.println(b); 16 b = in.read(); 17 System.out.println(b);//255 00000000 00000000 00000000 11111111 18 b = in.read(); 19 System.out.println(b);//127 00000000 00000000 00000000 01111111 20 b = in.read(); 21 System.out.println(b);//128 00000000 00000000 00000000 10000000 22 b = in.read(); 23 System.out.println(b);//-1 11111111 11111111 11111111 11111111 24 in.close(); 25 26 ByteArrayOutputStream out = new ByteArrayOutputStream();//默认开辟32byte的数组作为输出目标 27 //如果满了就自动扩容 28 //out:[0,0,0,0,0,0,0,.....] 29 // 30 out.write(1);//[1,0,0,0,0,0,....] 31 out.write(-2);//[1,fe,0,0,0,0,0,....] 32 out.write(-1);//[1,fe,ff,0,0,0,0,....] 33 out.close(); 34 byte[] buf = out.toByteArray();//复制有效部分 35 IOUtils.print(buf);//[01, fe, ff ] 36 } 37 38 } 39 40 41