[19/04/01-星期一] IO技术_字节流分类总结(含字节数组(Array)流、字节数据(Data)流、字节对象(Object)流)
一、字节流分类概括
-->1、ByteArrayInputStream /ByteArrayOutputStream(数组字节输入输出)
InputStream/OutputStream -->2、FileInputStream/FileOutputStream(文件字节输入输出流【参考19.03.30文章】)
(四大抽象类之二,与Reader/Writer平辈) -->3、ObjectInputStream/ObjectOutputStream(对象字节输入输出流)
-->4、FilterInputStream/FilterOutputStream(加装饰器的输入/输出流)-----》》
----------------》》4-1:BufferedInputStream/BufferedOutputStream(带缓冲区的字节流) 【参考19.3.30文章】
----------------》》4-2:DataInputStream/DataOutputStream(数据输入/输出流)
----------------》》4-3:【独有】PrintStream打印输出流、处理流
1、ByteArrayInputStream /ByteArrayOutputStream(数组字节输入输出)
1 /**学习 1、文件数组字节流 (InputStream/OutputStream的亲儿子) 2 * ByteArrayInputStream /ByteArrayOutputStream(文件数组字节输入输出)与FileInputStream/FileOutputStream平辈 3 * 以前源头:本地电脑硬盘文件<-----操作系统----->Java虚拟机 。以前的FileInputStream/FileOutputStream的用法 4 * 所以每次都要通知操作系统释放内存 5 * 现在源头:本地电脑的另外一块内存/网络上的一块内存/远程服务器的一块内存 ,看成一块字节数组,所以可以让Java虚拟机直接访问 6 * 与操作系统无关,使用完后由垃圾回收机制管理,不用释放内存。风格统一,可以释放内存,是实际没作用。 7 * 1、任何东西都可以转成字节数组 2、字节数组不要太大 8 * 9 * 写数据:ByteArrayOutputStream 10 * 不需要指定文件目的地,这点与FileOutputStream(如需要自己指定个"dest.txt")不同,因为是内存写的,大小不好管理 11 * 可以不用释放操作 12 * 13 */ 14 package cn.sxt.test; 15 16 import java.io.ByteArrayInputStream; 17 import java.io.ByteArrayOutputStream; 18 import java.io.IOException; 19 20 public class Test_0401_ArrayStream { 21 public static void main(String[] args) throws IOException { 22 //1、创建源 字符串,编码成字节数组 23 byte[] src="I am angry,Are you OK!".getBytes(); 24 //2、选择流 25 ByteArrayInputStream bStream=new ByteArrayInputStream(src); 26 //3、选择操作 27 int len=0; 28 /*3-1: 不借助数组,简单粗暴 29 while ((len=bStream.read())!=-1) { //等于说读一个字节输出一个字节 30 System.out.print((char)len); 31 }*/ 32 //4、可以释放内存,保持统一 ,但其方法是个空方法 ,没什么卵用 33 bStream.close(); 34 //3-2 :借助数组,常用方法 35 byte butter[] =new byte[5]; 36 /* 37 while ((len=bStream.read(butter))!=-1) {//往butter读取每5个字符,解码换行输出一回。 循环往复 38 String msg=new String(butter,0,butter.length); 39 System.out.println(msg); 40 }*/ 41 42 //-------------分隔符----写数据(往内存中写,这里内存实际就是输出流的缓冲区)--- 43 44 ByteArrayOutputStream bStream2=new ByteArrayOutputStream();//默认构建一个32字节的缓冲区,且内容会自动增加) 45 bStream2.write(src);//把经过编码后的字节src 写入到内存中,也就是输出流缓冲区 46 byte[] dest=bStream2.toByteArray();//向缓冲区取数据 47 System.out.println(dest.length+"-->>"+new String(dest,0,dest.length));//数据展示 48 49 } 50 51 }
【综合练习-复制图片】
1 /** 复制一张图片 所有东西都能读到字节数组中 2 * 前面4种流的综合 3 * ByteArrayInputStream /ByteArrayOutputStream FileInputStream/FileOutputStream 4 * 图片---FileInputStream------->(借助程序作中转,Java虚拟机)---ByteArrayOutputStream------>字节数组中(内存) 5 * 字节数组(内存)----ByteArrayInputStream---->(借助程序作中转,Java虚拟机)---FileOutputStream-------->图片 6 * 7 */ 8 package cn.sxt.test; 9 10 import java.io.ByteArrayInputStream; 11 import java.io.ByteArrayOutputStream; 12 import java.io.FileInputStream; 13 import java.io.FileOutputStream; 14 import java.io.IOException; 15 import java.io.InputStream; 16 import java.io.OutputStream; 17 18 public class Test_0401_CopyImage { 19 public static void main(String[] args) throws IOException { 20 byte[] srcFile= fileToByteArray("SongYi.jpg"); 21 System.out.println(srcFile.length);//输出源文件图片的大小 22 ByteArrayToFile(srcFile, "SongYi_copy.jpg"); 23 24 25 } 26 //1、图片到字节数组 传进去一个源文件路径。 图片-->程序--->字节数组 27 public static byte[] fileToByteArray(String srcFilePath) throws IOException { 28 29 InputStream iStream=new FileInputStream(srcFilePath);//图片-->程序 30 ByteArrayOutputStream oStream=new ByteArrayOutputStream();//程序-->字节数组 31 byte buffer[]=new byte[1024*10]; //缓冲数组 32 int len=0; //分段读取 33 while ((len=iStream.read(buffer))!=-1) { 34 oStream.write(buffer,0,len); 35 36 } 37 iStream.close(); 38 39 return oStream.toByteArray(); 40 41 } 42 43 44 //2、字节数组到图片 字节数组--->程序--->要复制的图片 45 public static void ByteArrayToFile(byte[] src,String destFilePath) throws IOException { 46 47 ByteArrayInputStream iStream1=new ByteArrayInputStream(src);//字节数组-->程序 48 49 OutputStream oStream1=new FileOutputStream(destFilePath);//程序--->要复制的图片 50 51 byte buffer1[]=new byte[1024*10]; //缓冲数组 52 int len=0; //分段读取 53 while ((len=iStream1.read(buffer1))!=-1) { 54 oStream1.write(buffer1,0,len); 55 } 56 oStream1.close(); 57 } 58 59 60 }
2、ObjectInputStream/ObjectOutputStream(对象字节输入输出流)
当两个进程远程通信时,彼此可以发送各种类型的数据。 无论是何种类型的数据,都会以二进制序列的形式在网络上传送。
比如,我们可以通过http协议发送字符串信息;我们也可以在网络上直接发送Java对象。发送方需要把这个Java对象转换为字节序列,
才能在网络上传送;接收方则需要把字节序列再恢复为Java对象才能正常读取。把Java对象转换为字节序列的过程称为对象的序列化。
把字节序列恢复为Java对象的过程称为对象的反序列化。
对象序列化的作用有如下两种:
1. 持久化: 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中,比如:休眠的实现。以后服务器session管理,hibernate将对象持久化实现。
2. 网络通信:在网络上传送对象的字节序列。比如:服务器之间的数据通信、对象传递。
【代码示例】
1 /**2、对象流 ObjectStream 2 * 输出流:序列化 3 * 输入流:反序列化 4 *ObjectOutputStream 对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化, 5 *把得到的字节序列写到一个目标输出流中。这个目标输入流可能是文件,数据库,内存中。 6 * 7 ObjectInputStream 对象输入流,它的readObject()方法从一个源输入流中读取字节序列 8 ,再把它们反序列化为一个对象,并将其返回。 9 10 只有实现了Serializable接口的类的对象才能被序列化。 Serializable接口是一个空接口,只起到标记作用。 11 * 12 * 不是所有的对象都可序列化 13 */ 14 package cn.sxt.test; 15 16 import java.io.ByteArrayInputStream; 17 import java.io.ByteArrayOutputStream; 18 import java.io.IOException; 19 import java.io.ObjectInputStream; 20 import java.io.ObjectOutputStream; 21 import java.security.PrivateKey; 22 import java.util.Date; 23 24 import javax.tools.JavaCompiler; 25 26 27 28 public class Test_0401_ObjectStream { 29 public static void main(String[] args) throws IOException, ClassNotFoundException { 30 31 ByteArrayOutputStream baos=new ByteArrayOutputStream(); 32 ObjectOutputStream dos=new ObjectOutputStream(baos); 33 34 35 dos.writeUTF("编码"); 36 dos.writeInt(345); 37 //写入:序列化 38 dos.writeObject("编码好痛苦");//字符串也是一个对象 39 dos.writeObject(new Date()); 40 dos.writeObject(new Employee("李白",3458.4)); 41 42 dos.flush(); 43 44 //错误原因:byte[] datas=baos.toByteArray();放在了oos.writeInt(14);oos.flush();的前边,应该在后边 45 byte[] datas=baos.toByteArray(); 46 47 //DataInputStream dis=new DataInputStream(new ByteArrayInputStream(datas)); 48 49 ByteArrayInputStream bis=new ByteArrayInputStream(datas); 50 ObjectInputStream dis=new ObjectInputStream(bis); 51 52 //读取 :反序列化 53 String msg=dis.readUTF(); 54 System.out.println(msg); 55 System.out.println(dis.readInt()); 56 System.out.println(dis.readObject()); 57 System.out.println(dis.readObject()); 58 //System.out.println(dis.readObject()); 59 //同理前边的字符串类也可以这样操作 60 Object employee=dis.readObject(); 61 if (employee instanceof Employee) {//如果employee 是Employee类的实例化对象则输出 62 Employee employeetemp=(Employee)employee;//而且可以强制转换一下 63 System.out.println(employeetemp); 64 65 System.out.println("名字:"+employeetemp.getName()); 66 //可以看出薪水的属性加了transient透明修饰,这里的返回值为0.0 67 System.out.println("薪水:"+employeetemp.getSalary()); 68 69 } 70 71 72 } 73 74 75 } 76 77 //自己定义的一个类,称之为Javabean封装数据用的。这里还必须要序列化(Serializable),加个牌照,否则虚拟机后拦截的 78 class Employee implements java.io.Serializable{ 79 private String name; 80 81 private transient double salary;//transient:短暂的,临时的 这里翻译为透明的、隐身的.敏感数据可以用。这里不需要序列化 82 83 //按键alt+shift+s 出现上面菜单 无参构造 : 快捷键 下边 Generate Constructors from Supperclass.. 84 //.根据基类的构造函数生成构造函数,生成和基类参数相同的构造函数,并同时调用基类的构造函数。 85 public Employee() { 86 super(); 87 } 88 89 //构造方法 Generate Constructor using Fields... 90 // 使用类属性生成构造函数,就是说会生成使用你定义好的属性作为参数的构造函数。 91 public Employee(String name, double salary) { 92 super(); 93 this.name = name; 94 this.salary = salary; 95 } 96 97 98 public String getName() { 99 return name; 100 } 101 102 103 public void setName(String name) { 104 this.name = name; 105 } 106 107 108 public double getSalary() { 109 return salary; 110 } 111 112 113 public void setSalary(double salary) { 114 this.salary = salary; 115 } 116 117 //重写 toString 方法 118 public String toString() { 119 return "雇员 [name=" + name + ", salary=" + salary + "]"; 120 } 121 122 123 124 125 126 }
4-2:DataInputStream/DataOutputStream(数据输入/输出流)
【代码示例】
1 /** 2 *4-2:DataInputStream/DataOutputStream(数据输入/输出流) 3 *用途:方便处理8大基本数据类型 4 *1) 先写出后读取 5 *2) 读取顺序和写出保持一致 6 * 7 */ 8 package cn.sxt.test; 9 10 import java.io.ByteArrayInputStream; 11 import java.io.ByteArrayOutputStream; 12 import java.io.DataInputStream; 13 import java.io.DataOutputStream; 14 import java.io.FileInputStream; 15 import java.io.FileOutputStream; 16 import java.io.IOException; 17 18 19 public class Test_0401_DataStream { 20 public static void main(String[] args) throws IOException { 21 //先搞个节点流ByteArrayInputStream /ByteArrayOutputStream或FileInputStream/FileOutputStream 22 //然后让装饰流去操作他们,否则装饰流就是无源之水,无本之木。//默认构建一个32字节的缓冲区,且内容会自动增 23 //ByteArrayOutputStream bos=new ByteArrayOutputStream();//这个流不用关闭 24 25 //写出,使用数组作为节点流时 26 FileOutputStream out = new FileOutputStream("D:/a1.txt"); 27 DataOutputStream dos=new DataOutputStream(out); 28 29 //byte[] datas=bos.toByteArray();//转成字节放在字节数组中 30 31 dos.writeChar('a'); 32 dos.writeInt(10); 33 dos.writeDouble(Math.random()); 34 dos.writeBoolean(true); 35 dos.writeUTF("Are you OK"); 36 dos.flush(); 37 38 //读取顺序与写入保持一致 39 //ByteArrayInputStream bis=new ByteArrayInputStream(datas);//从字节数组中读取 40 FileInputStream in = new FileInputStream("D:/a1.txt"); 41 DataInputStream dis=new DataInputStream(in); 42 43 System.out.println("char: " + dis.readChar()); 44 System.out.println("int: " + dis.readInt()); 45 System.out.println("double: " + dis.readDouble()); 46 System.out.println("boolean: " + dis.readBoolean()); 47 System.out.println("String: " + dis.readUTF()); 48 49 dos.close(); 50 dis.close(); 51 52 //数组作为字节流 53 /* ByteArrayOutputStream baos=new ByteArrayOutputStream(); 54 DataOutputStream dos=new DataOutputStream(baos); 55 56 dos.writeUTF("编码"); 57 dos.writeInt(345); 58 dos.flush(); 59 60 byte[] datas=baos.toByteArray(); 61 62 //DataInputStream dis=new DataInputStream(new ByteArrayInputStream(datas)); 63 64 ByteArrayInputStream bis=new ByteArrayInputStream(datas); 65 DataInputStream dis=new DataInputStream(bis);*/ 66 67 } 68 69 }
4-3:【独有】PrintStream打印输出流、处理流
【代码示例】
1 /** 2 * 学习4-3:打印流、处理流PrintStream 3 * 4 */ 5 package cn.sxt.test; 6 7 import java.io.FileDescriptor; 8 import java.io.FileNotFoundException; 9 import java.io.FileOutputStream; 10 import java.io.PrintStream; 11 import java.io.PrintWriter; 12 13 public class Test_0401_PrintStream { 14 public static void main(String[] args) throws FileNotFoundException { 15 PrintStream pStream=System.out; 16 pStream.println("人生如逆旅"); //输出内容到控制台 17 pStream.println(true); 18 //2个打印流的效果一样 19 PrintWriter pWriter=new PrintWriter(new FileOutputStream("print3.txt"),true); 20 pWriter.print("学习Java"); 21 pWriter.close(); 22 23 FileOutputStream file=new FileOutputStream("print.txt"); 24 PrintStream pStream2=new PrintStream(file,true);//在里面放个字节流 true:使用自动刷新的功能 25 pStream2.println(false); //输出内容到文件 26 pStream2.println("人生苦短,学习要趁早!"); 27 pStream2.println("java is best"); 28 29 //重定向输出端 把原本输出到控制台的输出到文件中去 30 System.setOut(pStream2); 31 pStream2.println("改变自己"); 32 //重定向回去控制台 FileDescriptor.out 标准的输入输出端 33 FileOutputStream file2=new FileOutputStream(FileDescriptor.out); 34 PrintStream pStream3=new PrintStream(file2,true); 35 System.setOut(pStream3); 36 pStream3.println("back"); 37 38 /*//效果一样 39 System.setOut(pStream); 40 pStream.print("回来了");*/ 41 42 pStream.close(); 43 pStream2.close(); 44 pStream3.close(); 45 } 46 47 }