[19/04/01-星期一] IO技术_字节流分类总结(含字节数组(Array)流、字节数据(Data)流、字节对象(Object)流)

时间:2021-10-07 12:02:01

一、字节流分类概括

-->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、文件数组字节流 (InputStream/OutputStream的亲儿子)
* ByteArrayInputStream /ByteArrayOutputStream(文件数组字节输入输出)与FileInputStream/FileOutputStream平辈
* 以前源头:本地电脑硬盘文件<-----操作系统----->Java虚拟机 。以前的FileInputStream/FileOutputStream的用法
* 所以每次都要通知操作系统释放内存
* 现在源头:本地电脑的另外一块内存/网络上的一块内存/远程服务器的一块内存 ,看成一块字节数组,所以可以让Java虚拟机直接访问
* 与操作系统无关,使用完后由垃圾回收机制管理,不用释放内存。风格统一,可以释放内存,是实际没作用。
* 1、任何东西都可以转成字节数组 2、字节数组不要太大
*
* 写数据:ByteArrayOutputStream
* 不需要指定文件目的地,这点与FileOutputStream(如需要自己指定个"dest.txt")不同,因为是内存写的,大小不好管理
* 可以不用释放操作
*
*/
package cn.sxt.test; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException; public class Test_0401_ArrayStream {
public static void main(String[] args) throws IOException {
//1、创建源 字符串,编码成字节数组
byte[] src="I am angry,Are you OK!".getBytes();
//2、选择流
ByteArrayInputStream bStream=new ByteArrayInputStream(src);
//3、选择操作
int len=0;
/*3-1: 不借助数组,简单粗暴
while ((len=bStream.read())!=-1) { //等于说读一个字节输出一个字节
System.out.print((char)len);
}*/
//4、可以释放内存,保持统一 ,但其方法是个空方法 ,没什么卵用
bStream.close();
//3-2 :借助数组,常用方法
byte butter[] =new byte[5];
/*
while ((len=bStream.read(butter))!=-1) {//往butter读取每5个字符,解码换行输出一回。 循环往复
String msg=new String(butter,0,butter.length);
System.out.println(msg);
}*/ //-------------分隔符----写数据(往内存中写,这里内存实际就是输出流的缓冲区)--- ByteArrayOutputStream bStream2=new ByteArrayOutputStream();//默认构建一个32字节的缓冲区,且内容会自动增加)
bStream2.write(src);//把经过编码后的字节src 写入到内存中,也就是输出流缓冲区
byte[] dest=bStream2.toByteArray();//向缓冲区取数据
System.out.println(dest.length+"-->>"+new String(dest,0,dest.length));//数据展示 } }

【综合练习-复制图片】

 /** 复制一张图片 所有东西都能读到字节数组中
* 前面4种流的综合
* ByteArrayInputStream /ByteArrayOutputStream FileInputStream/FileOutputStream
* 图片---FileInputStream------->(借助程序作中转,Java虚拟机)---ByteArrayOutputStream------>字节数组中(内存)
* 字节数组(内存)----ByteArrayInputStream---->(借助程序作中转,Java虚拟机)---FileOutputStream-------->图片
*
*/
package cn.sxt.test; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream; public class Test_0401_CopyImage {
public static void main(String[] args) throws IOException {
byte[] srcFile= fileToByteArray("SongYi.jpg");
System.out.println(srcFile.length);//输出源文件图片的大小
ByteArrayToFile(srcFile, "SongYi_copy.jpg"); }
//1、图片到字节数组 传进去一个源文件路径。 图片-->程序--->字节数组
public static byte[] fileToByteArray(String srcFilePath) throws IOException { InputStream iStream=new FileInputStream(srcFilePath);//图片-->程序
ByteArrayOutputStream oStream=new ByteArrayOutputStream();//程序-->字节数组
byte buffer[]=new byte[1024*10]; //缓冲数组
int len=0; //分段读取
while ((len=iStream.read(buffer))!=-1) {
oStream.write(buffer,0,len); }
iStream.close(); return oStream.toByteArray(); } //2、字节数组到图片 字节数组--->程序--->要复制的图片
public static void ByteArrayToFile(byte[] src,String destFilePath) throws IOException { ByteArrayInputStream iStream1=new ByteArrayInputStream(src);//字节数组-->程序 OutputStream oStream1=new FileOutputStream(destFilePath);//程序--->要复制的图片 byte buffer1[]=new byte[1024*10]; //缓冲数组
int len=0; //分段读取
while ((len=iStream1.read(buffer1))!=-1) {
oStream1.write(buffer1,0,len);
}
oStream1.close();
} }

2、ObjectInputStream/ObjectOutputStream(对象字节输入输出流)

当两个进程远程通信时,彼此可以发送各种类型的数据。 无论是何种类型的数据,都会以二进制序列的形式在网络上传送。

比如,我们可以通过http协议发送字符串信息;我们也可以在网络上直接发送Java对象。发送方需要把这个Java对象转换为字节序列,

才能在网络上传送;接收方则需要把字节序列再恢复为Java对象才能正常读取。把Java对象转换为字节序列的过程称为对象的序列化。

把字节序列恢复为Java对象的过程称为对象的反序列化。

对象序列化的作用有如下两种:

1. 持久化: 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中,比如:休眠的实现。以后服务器session管理,hibernate将对象持久化实现。

2. 网络通信:在网络上传送对象的字节序列。比如:服务器之间的数据通信、对象传递。

【代码示例】

 /**2、对象流 ObjectStream
* 输出流:序列化
* 输入流:反序列化
*ObjectOutputStream 对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,
*把得到的字节序列写到一个目标输出流中。这个目标输入流可能是文件,数据库,内存中。
*
ObjectInputStream 对象输入流,它的readObject()方法从一个源输入流中读取字节序列
,再把它们反序列化为一个对象,并将其返回。 只有实现了Serializable接口的类的对象才能被序列化。 Serializable接口是一个空接口,只起到标记作用。
*
* 不是所有的对象都可序列化
*/
package cn.sxt.test; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.PrivateKey;
import java.util.Date; import javax.tools.JavaCompiler; public class Test_0401_ObjectStream {
public static void main(String[] args) throws IOException, ClassNotFoundException { ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream dos=new ObjectOutputStream(baos); dos.writeUTF("编码");
dos.writeInt(345);
//写入:序列化
dos.writeObject("编码好痛苦");//字符串也是一个对象
dos.writeObject(new Date());
dos.writeObject(new Employee("李白",3458.4)); dos.flush(); //错误原因:byte[] datas=baos.toByteArray();放在了oos.writeInt(14);oos.flush();的前边,应该在后边
byte[] datas=baos.toByteArray(); //DataInputStream dis=new DataInputStream(new ByteArrayInputStream(datas)); ByteArrayInputStream bis=new ByteArrayInputStream(datas);
ObjectInputStream dis=new ObjectInputStream(bis); //读取 :反序列化
String msg=dis.readUTF();
System.out.println(msg);
System.out.println(dis.readInt());
System.out.println(dis.readObject());
System.out.println(dis.readObject());
//System.out.println(dis.readObject());
//同理前边的字符串类也可以这样操作
Object employee=dis.readObject();
if (employee instanceof Employee) {//如果employee 是Employee类的实例化对象则输出
Employee employeetemp=(Employee)employee;//而且可以强制转换一下
System.out.println(employeetemp); System.out.println("名字:"+employeetemp.getName());
//可以看出薪水的属性加了transient透明修饰,这里的返回值为0.0
System.out.println("薪水:"+employeetemp.getSalary()); } } } //自己定义的一个类,称之为Javabean封装数据用的。这里还必须要序列化(Serializable),加个牌照,否则虚拟机后拦截的
class Employee implements java.io.Serializable{
private String name; private transient double salary;//transient:短暂的,临时的 这里翻译为透明的、隐身的.敏感数据可以用。这里不需要序列化 //按键alt+shift+s 出现上面菜单 无参构造 : 快捷键 下边 Generate Constructors from Supperclass..
//.根据基类的构造函数生成构造函数,生成和基类参数相同的构造函数,并同时调用基类的构造函数。
public Employee() {
super();
} //构造方法 Generate Constructor using Fields...
// 使用类属性生成构造函数,就是说会生成使用你定义好的属性作为参数的构造函数。
public Employee(String name, double salary) {
super();
this.name = name;
this.salary = salary;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public double getSalary() {
return salary;
} public void setSalary(double salary) {
this.salary = salary;
} //重写 toString 方法
public String toString() {
return "雇员 [name=" + name + ", salary=" + salary + "]";
} }

4-2:DataInputStream/DataOutputStream(数据输入/输出流)

【代码示例】

 /**
*4-2:DataInputStream/DataOutputStream(数据输入/输出流)
*用途:方便处理8大基本数据类型
*1) 先写出后读取
*2) 读取顺序和写出保持一致
*
*/
package cn.sxt.test; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException; public class Test_0401_DataStream {
public static void main(String[] args) throws IOException {
//先搞个节点流ByteArrayInputStream /ByteArrayOutputStream或FileInputStream/FileOutputStream
//然后让装饰流去操作他们,否则装饰流就是无源之水,无本之木。//默认构建一个32字节的缓冲区,且内容会自动增
//ByteArrayOutputStream bos=new ByteArrayOutputStream();//这个流不用关闭 //写出,使用数组作为节点流时
FileOutputStream out = new FileOutputStream("D:/a1.txt");
DataOutputStream dos=new DataOutputStream(out); //byte[] datas=bos.toByteArray();//转成字节放在字节数组中 dos.writeChar('a');
dos.writeInt(10);
dos.writeDouble(Math.random());
dos.writeBoolean(true);
dos.writeUTF("Are you OK");
dos.flush(); //读取顺序与写入保持一致
//ByteArrayInputStream bis=new ByteArrayInputStream(datas);//从字节数组中读取
FileInputStream in = new FileInputStream("D:/a1.txt");
DataInputStream dis=new DataInputStream(in); System.out.println("char: " + dis.readChar());
System.out.println("int: " + dis.readInt());
System.out.println("double: " + dis.readDouble());
System.out.println("boolean: " + dis.readBoolean());
System.out.println("String: " + dis.readUTF()); dos.close();
dis.close(); //数组作为字节流
/* ByteArrayOutputStream baos=new ByteArrayOutputStream();
DataOutputStream dos=new DataOutputStream(baos); dos.writeUTF("编码");
dos.writeInt(345);
dos.flush(); byte[] datas=baos.toByteArray(); //DataInputStream dis=new DataInputStream(new ByteArrayInputStream(datas)); ByteArrayInputStream bis=new ByteArrayInputStream(datas);
DataInputStream dis=new DataInputStream(bis);*/ } }

4-3:【独有】PrintStream打印输出流、处理流

【代码示例】

 /**
* 学习4-3:打印流、处理流PrintStream
*
*/
package cn.sxt.test; import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter; public class Test_0401_PrintStream {
public static void main(String[] args) throws FileNotFoundException {
PrintStream pStream=System.out;
pStream.println("人生如逆旅"); //输出内容到控制台
pStream.println(true);
//2个打印流的效果一样
PrintWriter pWriter=new PrintWriter(new FileOutputStream("print3.txt"),true);
pWriter.print("学习Java");
pWriter.close(); FileOutputStream file=new FileOutputStream("print.txt");
PrintStream pStream2=new PrintStream(file,true);//在里面放个字节流 true:使用自动刷新的功能
pStream2.println(false); //输出内容到文件
pStream2.println("人生苦短,学习要趁早!");
pStream2.println("java is best"); //重定向输出端 把原本输出到控制台的输出到文件中去
System.setOut(pStream2);
pStream2.println("改变自己");
//重定向回去控制台 FileDescriptor.out 标准的输入输出端
FileOutputStream file2=new FileOutputStream(FileDescriptor.out);
PrintStream pStream3=new PrintStream(file2,true);
System.setOut(pStream3);
pStream3.println("back"); /*//效果一样
System.setOut(pStream);
pStream.print("回来了");*/ pStream.close();
pStream2.close();
pStream3.close();
} }