第8次文章:其他流

  • 2019 年 10 月 8 日
  • 笔记

各位小伙伴儿,大家周末愉快哈

回到学校,开始科研,开始好好奋斗咯
一、节点流

1、字节数组 字节 节点流

在两台计算机上进行数据的相互的传输

输入流 :ByteArrayInputStream

使用方法:read(byte[] b,int off,int len) +close()

输出流 :ByteArrayOutputStream

使用方法:write(byte[] b,int off,int len) +toByteArray() + close() 不要使用多态

例如:

package com.peng.IO.others;    import java.io.BufferedInputStream;  import java.io.ByteArrayInputStream;  import java.io.ByteArrayOutputStream;  import java.io.IOException;  import java.io.InputStream;    public class ByteArrayDemo01 {    public static void main(String[] args) throws IOException {  read(write());  }  /**   * 写出操作   * 字节输出流与文件输出有些不同,因为字节输出流有新增方法,所以不可以使用多态   * @throws IOException   */  public static byte[] write() throws IOException {  //目标位置  byte[] dest ;  //选择流  这里有不同点:没有将目标位置和输出流进行关联  ByteArrayOutputStream bos = new ByteArrayOutputStream();  //操作 写出  String msg = "字节输入流与文件输入流一致";  byte[] info = msg.getBytes();  bos.write(info, 0, info.length);  //获取数据  dest = bos.toByteArray();  //释放资源  bos.close();  return dest;  }    /**   * 字节输入流(ByteArrayInputStream)与文件输入流一致(FileInputStream)   * @throws IOException   */  public static void read(byte[] src) throws IOException {  //数据源  使用外部传入的方式来获取    //选择流。通过流,打开另一端计算机的数据,所以不能在数据源的地方进行打印输出  InputStream is = new BufferedInputStream(//缓冲流  new ByteArrayInputStream(src)//节点流  );    //操作  byte[] info =new byte[1024];  int len = 0;  while(-1 != (len=is.read(info))) {  System.out.println(new String(info,0,len));  }    //释放资源  is.close();//此处的close是一个空命令,两台计算机之间不需要释放资源  }    }

在写出操作的时候,与文件输出流不同的是:字节输出流没有和写出的目标位置相关联,而是直接将内容写进字节数组输出流中,然后使用字节数组输出流将内容转化为字节数组,并返回给目标位置。

二、处理流

1、基本类型 + String 保留数据+类型

输入流:DateInputStream readXxx

输出流:DateOutputStream writeXxx

在之前的IO流中,我们仅仅是将字符相关的信息保存在了相应的文件中,却没有注意各个保存的内容参数的类型,比如int,double,float,long,String等等,那么这样的保存,在我们后期的调用相关数据时,难以快速确定各个参数的类型,所以会降低效率。现在使用DateInputStream和DateOutputStream时,就可以有效的避免这样的问题。保存数据的时候,同时保存数据相对应的类型。

例如下面的实例:

package com.peng.IO.others;    import java.io.BufferedInputStream;  import java.io.BufferedOutputStream;  import java.io.ByteArrayInputStream;  import java.io.ByteArrayOutputStream;  import java.io.DataInputStream;  import java.io.DataOutputStream;  import java.io.IOException;  import java.io.InputStream;    /**   * 数据类型(基本类型+String)处理流   * 在保存时,同时保存数据以及其对应的数据类型   */  public class DataDemo2 {    public static void main(String[] args) throws IOException {  byte[] data = write();  read(data);  System.out.println(data.length);  }    /**   * 数据+类型   从字节数组中读取   * @throws IOException   */  public static void read(byte[] src) throws IOException {    //选择流  //选择字节输入流  InputStream is = new ByteArrayInputStream(src);  DataInputStream dis = new DataInputStream(  new BufferedInputStream(  is  )  );    //操作 读取的顺序必须与写出的顺序一致 必须存在才能读取  double point = dis.readDouble();  long num = dis.readLong();  String str = dis.readUTF();  System.out.println(point+"--->"+num+"--->"+str);  //释放资源  dis.close();  }    /**   * 数据+类型     输出到字节数组   * @param destPath   * @throws IOException   */  public static byte[] write() throws IOException {  double point = 2.5;  long num = 100L;  String str = "数据类型";    //创建目的地  byte[] dest = null;    //选择流  //选择字节数组输出流  ByteArrayOutputStream bos = new ByteArrayOutputStream();  DataOutputStream dos = new DataOutputStream(//数据类型处理流  new BufferedOutputStream(//缓冲处理流  bos//建立联系  )  );  //写出的顺序很重要,因为后续在告诉用户的过程中,需要告诉用户第几个参数是什么含义  dos.writeDouble(point);  dos.writeLong(num);  dos.writeUTF(str);  dos.flush();    //获取数据  dest = bos.toByteArray();    //释放资源  dos.close();  return dest;  }    }

在读取最后的写出结果时,可以直接识别出写出的结果是什么类型的,这样就可以大大的提高运行效率。

2、引用类型(对象) 保留数据+类型

反序列化:输入流:ObjectInputStream readObject()

序列化:输出流:ObjectOutputStream writeObject()

注意:

1)先序列化后反序列化;但序列化的顺序必须和序列化的顺序相同

2)不是所有的对象都可以序列化,需要对象实现接口java.io.Serializable

不是对象的所有属性都需要序列化,可以在不需要序列化的属性前面加上修饰符transient

例如:

1)创建Employee类,实现接口java.io.Serializable,同时利用transient修饰属性name,使得name不进行序列化。

package com.peng.IO.others;  /**   * 空接口只是一个标识   *   */  public class Employee implements java.io.Serializable{//此处是一个空接口  //transient表示该属性不需要序列化  private transient String name;  private double salary;    public Employee(String name, double salary) {  super();  this.name = name;  this.salary = salary;  }  public Employee() {    }  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;  }    }

2)对Employee对象进行序列化写出以及反序列化读取

package com.peng.IO.others;    import java.io.BufferedInputStream;  import java.io.BufferedOutputStream;  import java.io.File;  import java.io.FileInputStream;  import java.io.FileNotFoundException;  import java.io.FileOutputStream;  import java.io.IOException;  import java.io.ObjectInputStream;  import java.io.ObjectOutputStream;  import java.util.Arrays;    /**   * 数据类型(不仅限于基本数据类型,可以为引用数据类型,对象)处理流   * 1、序列化------>写出  ObjectOutputStream   * 2、反序列化----->读取 ObjectInputStream   *   * 不是所有的对象都可以序列化 java.io.NotSerializableException   * 不是所有的属性都需要序列化 transient   *   */  public class ObjectDemo01 {    public static void main(String[] args) throws IOException, ClassNotFoundException {  seri("E:\java学习\test\seri.txt");  read("E:\java学习\test\seri.txt");  }  //反序列化  读取  public static void read(String srcPath) throws FileNotFoundException, IOException, ClassNotFoundException {  //创建源  File src = new File(srcPath);  //选择流 ObjectInputStream  ObjectInputStream ois = new ObjectInputStream(  new BufferedInputStream(  new FileInputStream(src)  )  );    //操作  Object obj = ois.readObject();  if (obj instanceof Employee) {  Employee temp = (Employee) obj;  System.out.println(temp.getName());  System.out.println(temp.getSalary());  }    Object obj1 = ois.readObject();  int[] arr = (int[]) obj1;  System.out.println(Arrays.toString(arr));    //释放资源  ois.close();  }      //序列化  写出  public static void seri(String destPath) throws FileNotFoundException, IOException {  Employee temp = new Employee("鹏程万里",1000);  int[] arr = {1,2,3,4,5};  //创建源  File dest = new File(destPath);    //选择流ObjectOutputStream  ObjectOutputStream dos = new ObjectOutputStream(  new BufferedOutputStream(//缓冲流  new FileOutputStream(dest)//节点流  )  );    dos.writeObject(temp);  dos.writeObject(arr);  dos.flush();  dos.close();    }    }

3)查看结果

null  1000.0  [1, 2, 3, 4, 5]

由于我们使用了transient对Employee对象的name属性进行了修饰,所以在反序列化(读取)的时候,并没有输出Employee对象的name属性。

注意:

1)数组也属于一个对象,所以在序列化的时候,可以将数组也作为一个对象进行序列化和反序列化。

2)在反序列化(读取)时,读取的顺序必须与序列化(写出)的顺序相同,所以在写出的时候,需要注意写出的对象的顺序,避免后期读取的时候报错。

3)写出的文件内容是给计算机查看的内容,保留有各个属性的类型,所以我们查看路径“E:java学习testseri.txt”的内容时,所看到的是一堆乱码。如下图所示:

三、打印流

1、在java编程中,我们经常使用System.out.println()命令,将我们想要看到的变量打印在控制台上,便于我们看到变量的具体内容。而System.out.println()命令也属于IO流中的一种,也属于处理流中的一种。打印流的使用方法,也和其他的处理流的使用方法相同:

package com.peng.IO.others;    import java.io.BufferedOutputStream;  import java.io.File;  import java.io.FileNotFoundException;  import java.io.FileOutputStream;  import java.io.PrintStream;    /**   * PrintStream  打印流---->处理流   */  public class PrintStreamDemo01 {  public static void main(String[] args) throws FileNotFoundException {  System.out.println("test");  PrintStream ps = System.out;  ps.println(false);  //输出到文件  File src = new File("E:\java学习\test\print.txt");  ps = new PrintStream(//处理流  new BufferedOutputStream(//缓冲流  new FileOutputStream(src)//节点流--- 字节流  )  );  ps.println("peng is very good");  ps.flush();  ps.close();  }    }

通过上面的代码可以看出来,打印流(PrintStream)使用的是其自己的方法println方法,将字符串写出到目标文件中。

2、在打印流中,有几个基本的知识点这里提一下:

1)三个常量:

  • System.in 输入流—–键盘输入
  • System.out 输出流—–控制台输出
  • System.err 输出流—–控制台输出 其中,System.out和System.err的功能完全相同,都是将相应的提示信息输出到控制台上,唯一的差别就是在控制台上输出的信息的字体颜色不同,System.out输出到控制台上的字体颜色默认为黑色,而System.err输出到控制台上的字体颜色默认为红色。

2)重定向

由于在上述的三个常量,默认的输入与输出都是在控制台上进行,假如用户需要将信息输出到相应的文本文件中,而不是显示在控制台上,那么就需要使用重定向,将其输入与输出的位置进行重新关联。

例如:

package com.peng.IO.others;    import java.io.BufferedInputStream;  import java.io.BufferedOutputStream;  import java.io.File;  import java.io.FileDescriptor;  import java.io.FileInputStream;  import java.io.FileNotFoundException;  import java.io.FileOutputStream;  import java.io.InputStream;  import java.io.PrintStream;  import java.util.Scanner;    public class SystemDemo01 {    public static void main(String[] args) throws FileNotFoundException {  test();  }    public static void test() throws FileNotFoundException {  //重定向  System.setOut(new PrintStream(//本质上还是一个输出流 ---- 处理流  new BufferedOutputStream(  new FileOutputStream(  new File("E:/java学习/test/print.txt")  )  ),true  )  );  //此时的输出已经不在控制台中了,将所需要输出的字符输出到指定的文件中  System.out.println("test");//控制台----->文件  System.out.println("one produce two, two produce three,three produce all things.");    //重新回到控制台  System.setOut(new PrintStream(  new BufferedOutputStream(  new FileOutputStream(  FileDescriptor.out  )  ),true  )  );  System.out.println("back.........");  }    }

重定向主要使用三条命令进行实现:SetIn();SetOut();SetErr(),三条命令分别设定输入,输出,以及输出错误信息的位置。

控制台的目标位置同样使用三条命令进行实现:FileDescriptor.in;FileDescriptor.out;FileDescriptor.err,三条命令分别代表输入,输出和错误信息在返回到控制台上的位置。

四、装饰设计模式

1、类与类之间的关系

1)依赖:形参||局部变量

2)关联:属性

聚合:属性 整体与部分 不一致的生命周期 人与手

组合:属性 整体与部分 一致的生命周期 人与大脑

3)继承:父子类关系

4)实现:接口与实现类的关系

2、IO流中使用的属于装饰设计模式

也就是利用不同的处理流,对节点流进行包装处理。比如在老师讲课的时候,使用扩音器,就属于将老师的讲课声音进行了扩大,对原声进行了装饰。

例如:

1)我们先建立一个声音类

package com.peng.IO.pattern;    public class Voice {  private int voice = 10;  public Voice() {    }  public Voice(int voice) {  super();  this.voice = voice;  }  public int getVoice() {  return voice;  }  public void setVoice(int voice) {  this.voice = voice;  }  public void say() {  System.out.println(voice);  }  }

2)然后建立一个扩音器

package com.peng.IO.pattern;    public class Amplifier {  private Voice voice;  public Amplifier() {    }  public Amplifier(Voice voice) {  super();  this.voice = voice;  }  public Voice getVoice() {  return voice;  }  public void setVoice(Voice voice) {  this.voice = voice;  }  public void say() {  System.out.println(voice.getVoice()*1000);  }  }

3)最后应用一下

package com.peng.IO.pattern;    public class App {    public static void main(String[] args) {  Voice v =new Voice(20);  v.say();  Amplifier am = new Amplifier(v);  am.say();  }  }

最终的结果当然就是我们将声音的数值扩大了1000倍,这就是简单的使用了装饰模式。类比在IO流的使用上,我们依旧是首先利用处理流,使用处理流对缓冲流进行包装,然后再利用缓冲流对节点流或者字符流进行包装,最后实现我们需要的功能。

以上就是本周分享的内容咯!Java小白成长之路!Java小白在这里陪你一起学Java,一起向上奋斗!