前言

前面的文章主要讲了文件字符输入流FileWriter、文件字符输出流FileReader、文件字节输出流FileOutputStream、文件字节输入流FileInputStream,这些都是常见的流类。当然除了这些流类之外,Java还提供了很多的流类给用户使用,本文就看一下别的流。

管道流

管道流主要用于连接两个线程的通信。管道流也分为字节流(PipedInputStream、PipedOutputStream)和字符流(PipedReader、PipedWriter)。比如一个PipedInputStream必须和一个PipedOutputStream对象进行连接而产生一个通信管道,PipedOutputStream向管道中写入数据,PipedInputStream从管道中读取数据。管道流的工作如下图所示:

下面看一下管道流的用法。既然管道流的作用是用于线程间的通信,那么势必有发送线程和接收线程,两个线程通过管道流交互数据。首先写一个发送数据的线程:

  1. public class Sender implements Runnable
  2. {
  3. private PipedOutputStream out = new PipedOutputStream();
  4.  
  5. public PipedOutputStream getOutputStream()
  6. {
  7. return out;
  8. }
  9.  
  10. public void run()
  11. {
  12. String str = "Receiver, 你好!";
  13. try
  14. {
  15. out.write(str.getBytes()); // 向管道流中写入数据(发送)
  16. out.close();
  17. }
  18. catch (IOException e)
  19. {
  20. e.printStackTrace();
  21. }
  22. }
  23. }

用流写数据的时候注意关注一下,该流是否支持直接写String,不可以的话要用String的getBytes()方法获取字符串的字节。既然有一个发送数据的线程了,接下来来一个接收数据的线程:

  1. public class Receiver implements Runnable
  2. {
  3. private PipedInputStream in = new PipedInputStream();
  4.  
  5. public PipedInputStream getInputStream()
  6. {
  7. return in;
  8. }
  9.  
  10. public void run()
  11. {
  12. String s = null;
  13. byte b0[] = new byte[1024];
  14. try
  15. {
  16. int length = in.read(b0);
  17. if (-1 != length)
  18. {
  19. s = new String(b0, 0 , length);
  20. System.out.println("收到了以下信息:" + s);
  21. }
  22. in.close();
  23. } catch (IOException e)
  24. {
  25. e.printStackTrace();
  26. }
  27. }
  28. }

两个线程都有了,写一个main线程,利用管道输出流的connect方法连接管道输出流和管道输入流:

  1. public static void main(String[] args)
  2. {
  3. try
  4. {
  5. Sender sender = new Sender();
  6. Receiver receiver = new Receiver();
  7. Thread senderThread = new Thread(sender);
  8. Thread receiverThread = new Thread(receiver);
  9. PipedOutputStream out = sender.getOutputStream(); // 写入
  10. PipedInputStream in = receiver.getInputStream(); // 读出
  11. out.connect(in);// 将输出发送到输入
  12. senderThread.start();
  13. receiverThread.start();
  14. }
  15. catch (IOException e)
  16. {
  17. e.printStackTrace();
  18. }
  19. }

输出结果应该很明显了,大家都知道,接收线程接收到了来自发送线程通过管道流输出流发送的数据:

  1. 收到了以下信息:Receiver, 你好!

注意一下,PipedInputStream运用的是一个1024字节固定大小的循环缓冲区,写入PipedOutputStream的数据实际上保存到了对应的PipedInputStream的内部缓冲区。PipedInputStream执行读操作时,读取的数据实际上来自这个内部缓冲区。如果对应的PipedInputStream输入缓冲区已满,任何企图写入PipedOutputStream的线程都将被阻塞。而且这个写操作线程将一直阻塞,直至出现读取PipedInputStream的操作从缓冲区删除数据。

这意味着,向PipedOutputStream写入数据的线程不应该是负责从对应PipedInputStream读取数据的唯一线程(所以这里开了两个线程分别用于读写)。假定t线程试图一次对PipedOutputStream的write()方法的调用中向对应的PipedOutputStream写入2000字节的数据,在t线程阻塞之前,它最多能够写入1024字节的数据(PipedInputStream内部缓冲区的大小)。然而,一旦t被阻塞,读取PipedInputStream的操作就再也不能出现了,因为t是唯一读取PipedInputStream的线程,这样,t线程已经完全被阻塞。

对象流

序列化,在这篇文章中已经讲得比较清楚了,这一部分主要是再次简单过一下对象流的知识而已。

Java中提供了ObjectInputStream、ObjectOutputStream这两个类用于对象序列化操作,这两个类是用于存储和读取对象的输入输出流类,只要把对象中的所有成员变量都存储起来,就等于保存了这个对象,之后从保存的对象之中再将对象读取进来就可以继续使用此对象。ObjectInputStream、ObjectOutputStream可以帮助开发者完成保存和读取对象成员变量取值的过程,但要求读写或存储的对象必须实现了Serializable接口。

看一下例子,先来一个实现了Serializable接口的实体类Person:

  1. public class Person implements Serializable
  2. {
  3. /**
  4. * 序列化
  5. */
  6. private static final long serialVersionUID = 7827863437931135333L;
  7.  
  8. private transient String name;
  9. private int age;
  10. private final static String sex = "man";
  11.  
  12. public Person(String name, int age)
  13. {
  14. this.name = name;
  15. this.age = age;
  16. }
  17.  
  18. public String toString()
  19. {
  20. return "姓名:" + this.name + ", 年龄:" + this.age + ", 性别:" + sex;
  21. }
  22. }

调用ObjectOutputStream和ObjectInputStream写一个序列化和反序列化的方法,我现在D盘下没有"serializable.txt":

  1. public static void main(String[] args) throws Exception
  2. {
  3. File file = new File("D:/serializable.txt");
  4. serializable(file);
  5. deserializable(file);
  6. }
  7.  
  8. // 序列化对象方法
  9. public static void serializable(File file) throws Exception
  10. {
  11. OutputStream outputFile = new FileOutputStream(file);
  12. ObjectOutputStream oos = new ObjectOutputStream(outputFile);
  13. oos.writeObject(new Person("张三", 25));
  14. oos.close();
  15. }
  16.  
  17. // 反序列化对象方法
  18. public static void deserializable(File file) throws Exception
  19. {
  20. InputStream inputFile = new FileInputStream(file);
  21. ObjectInputStream ois = new ObjectInputStream(inputFile);
  22. Person p = (Person)ois.readObject();
  23. System.out.println(p);
  24. }

现在运行一下,D盘下多了一个"serializable.txt",文件里面的内容是:

看到乱码,因为序列化之后本身就是按照一定的二进制格式组织的文件,这些二进制格式不能被文本文件所识别,所以乱码也是正常的。

当然,控制台上也是有输出的:

  1. 姓名:null 年龄:25, 性别:man

这证明了被transient修饰的成员变量不会被序列化。

Java IO5:管道流、对象流的更多相关文章

  1. Java自学-I/O 对象流

    Java 对象流 ObjectInputStream,ObjectOutputStream 对象流指的是可以直接把一个对象以流的形式传输给其他的介质,比如硬盘 一个对象以流的形式进行传输,叫做序列化. ...

  2. 用非常硬核的JAVA序列化手段实现对象流的持久化保存

    目录 背景 对象流的概念 对象流实例 引入一张组织结构图 定义组织架构图的类 类的完整结构 用对象流保存组织架构的对象信息 核心代码 用对象流读取文件并输出 核心代码 总结 背景 在OOP(面向对象编 ...

  3. JAVA笔记12__字节、字符缓冲流/打印流/对象流/

    /** * !!:以后写流的时候一定要加入缓冲!! * 对文件或其它目标频繁的读写操作,效率低,性能差. * 缓冲流:好处是能更高效地读写信息,原理是将数据先缓冲起来,然后一起写入或读取出来. * * ...

  4. JAVA_基础IO流对象流(三)

    处理流:对象流 ObjectInputStream和OjbectOutputSteam用于存储和读取基本数据类型数据或对象的处理流.可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来. ...

  5. java学习之IO对象流

    //注意对象类要打标记实现Serializable接口 package com.gh; import java.io.FileInputStream; import java.io.FileNotFo ...

  6. Java网络多线程编程:对象流错误导致Connection reset

    Java网络多线程编程--对象流错误导致Connection reset 在老韩的网络多线程编程实战项目中,发生了如下报错: 服务器端和客户端均发生了报错,在确定相应对象流代码完全没有问题之后,回归定 ...

  7. io流(对象流总结)

    对象流 对象流就是对引用数据类型进行操作 序列化:将对象的状态信息转换为可以存储或传输的形式的过程,因此类需要序列化后才可以存储到文件中 对象输出流: 很简单,就三句话,将把一个对象导入指定文件中,要 ...

  8. day03 对象流与序列化

    对象流 java.io.ObjectOutputStream和ObjectInputSteam 对象流是一对高级流,在流连接中的作用是进行对象的序列化与反序列化. 对象序列化:将一个java对象按照其 ...

  9. Java IO7:管道流、对象流

    前言 前面的文章主要讲了文件字符输入流FileWriter.文件字符输出流FileReader.文件字节输出流FileOutputStream.文件字节输入流FileInputStream,这些都是常 ...

随机推荐

  1. sql 合并列

    1.合并一列用“ ,”号隔开. 如下图: 这样的一列我想直接在sql里面合并最后变成:586,444,444,444,444这样的效果,平常的做法是直接把这列数据取出来,在前端循环加上逗号,但其实是可 ...

  2. html label 标签的 for 属性

    如果您在 label 元素内点击文本,就会触发此控件.就是说,当用户选择该标签时,浏览器就会自动将焦点转到和标签相关的表单控件上. 有两种使用方法: 方法1 使用for属性 <label for ...

  3. HTML5画布(线条、渐变)

    绘制直线时,一般会用到moveTo与lineTo两种方法. 案例1: <!DOCTYPE html><html><head lang="en"> ...

  4. jQuery插件学习(一)

    由于项目开发需要,经常会用到一些jquery插件,但网上已有的插件常常又不能100%满足业务需求,所以就想自己能看懂插件的代码,进行一些功能上的改动和补充,或者能自己自定义插件就更好了.所以这段时间会 ...

  5. [转]jQuery插件开发精品教程,让你的jQuery提升一个台阶

    原文链接:http://www.cnblogs.com/Wayou/p/jquery_plugin_tutorial.html 要说jQuery 最成功的地方,我认为是它的可扩展性吸引了众多开发者为其 ...

  6. python代码风格规范

    类注释模板: :: class AnotherClass: """ 类注释 """ def method(self, arg1, arg2, ...

  7. PostgreSQL的时间函数使用整理

    PG的时间函数使用整理如下 1.获取系统时间函数 select now(); --2012-05-12 18:51:59.562+08 select current_timestamp; --2012 ...

  8. Winform不用窗体之间传值

    1 先构建一个类,内容如下: namespace TravelForm { public sealed class Setting { private static volatile Setting ...

  9. 地址重写--Java中urlrewriter的使用

    最近公司以前的一个项目需要升级改版,其中的一个模块是使用Struts2做的不需要改动,但是需要将其从之前的项目里面剥离出来,看了看官网,发现所有的链接访问的静态地址,以为是FreeMarker实现的, ...

  10. oracle pipelined返回值函数 针对数据汇总统计 返回结果集方法

    近期需要一个汇总统计,由于数据太多,数据量太大所以在java程序中实现比较困难.若用后台程序统计,数据不能保证实时,同时实现周期比较长.顾使用函数返回结果集的方式,在不增加临时表的情况下实时获取数据. ...