关闭

Java IO 7:管道流、对象流

标签: IONIOjava
157人阅读 评论(0) 收藏 举报
分类:

前言

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

 

管道流

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

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

复制代码
public class Sender implements Runnable
{
    private PipedOutputStream out = new PipedOutputStream();
    
    public PipedOutputStream getOutputStream()
    {
        return out;
    }
    
    public void run()
    {
        String str = "Receiver, 你好!";
        try
        {
            out.write(str.getBytes()); // 向管道流中写入数据(发送)
            out.close();
        } 
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }    
}
复制代码

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

复制代码
public class Receiver implements Runnable
{
    private PipedInputStream in = new PipedInputStream();
    
    public PipedInputStream getInputStream()
    {
        return in;
    }
    
    public void run()
    {
        String s = null;
        byte b0[] = new byte[1024];
        try
        {
            int length = in.read(b0);
            if (-1 != length)
            {
                s = new String(b0, 0 , length);
                System.out.println("收到了以下信息:" + s);
            }
            in.close();
        } catch (IOException e)
        {
            e.printStackTrace();
        }
    }
}
复制代码

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

复制代码
public static void main(String[] args)
{
    try
    {
        Sender sender = new Sender();
        Receiver receiver = new Receiver();
        Thread senderThread = new Thread(sender);
        Thread receiverThread = new Thread(receiver);
        PipedOutputStream out = sender.getOutputStream(); // 写入
        PipedInputStream in = receiver.getInputStream(); // 读出
        out.connect(in);// 将输出发送到输入
        senderThread.start();
        receiverThread.start();
    } 
    catch (IOException e)
    {
        e.printStackTrace();
    } 
}
复制代码

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

收到了以下信息: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:

复制代码
public class Person implements Serializable
{
    /**
     * 序列化
     */
    private static final long serialVersionUID = 7827863437931135333L;
    
    private transient String     name;
    private int                    age;
    private final static String sex = "man";
    
    public Person(String name, int age)
    {
        this.name = name;
        this.age = age;
    }
    
    public String toString()
    {
        return "姓名:" + this.name + ", 年龄:" + this.age + ", 性别:" + sex;
    }
}
复制代码

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

复制代码
public static void main(String[] args) throws Exception
{
    File file = new File("D:/serializable.txt");
    serializable(file);
    deserializable(file);
}
    
// 序列化对象方法
public static void serializable(File file) throws Exception
{
    OutputStream outputFile = new FileOutputStream(file);
    ObjectOutputStream oos = new ObjectOutputStream(outputFile);
    oos.writeObject(new Person("张三", 25));
    oos.close();
}
    
// 反序列化对象方法
public static void deserializable(File file) throws Exception
{
    InputStream inputFile = new FileInputStream(file);
    ObjectInputStream ois = new ObjectInputStream(inputFile);
    Person p = (Person)ois.readObject();
    System.out.println(p);
}
复制代码

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

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

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

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

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

0
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

Java——IO流读写对象及流操作规律

IO流 概述:IO流就是用来进行数据的输入输出操作的一个缓冲区。 按操作的对象不同可分为:    1、对字符操作              Reader和Writer    ...
  • oZackAeris
  • oZackAeris
  • 2015-07-28 17:07
  • 2477

java io流详解(二)对象输入输出流

1.对象输入输出流 ObjectOutputStream和ObjectInputStream可以用来实现对象序列化和反序列化操作。一般操作对象时,对象是存在内存中的,如果希望将对象保存在硬盘上,或者...
  • kaishizhangcheng
  • kaishizhangcheng
  • 2016-09-08 21:46
  • 2979

Java的IO流与对象的序列化浅谈

今天再次回顾了一些关于java IO流的知识。虽然以前会点IO的方面的编程,但是还是知其然不知其所以然。 首先上一张IO流的主要家族图吧。           该图给出了IO流的具...
  • LULEI1217
  • LULEI1217
  • 2016-01-16 13:54
  • 1971

『黑马程序员』---java--IO--对象序列化-管道流

----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------ 直接操作对象的流(对象的持久化,序列化,可串行性) Obje...
  • u012176021
  • u012176021
  • 2014-02-06 12:15
  • 645

黑马程序员《java基础总结(十四)》(IO流<管道流、序列化对象>)

管道流:管道读取流和管道写入流可以像管道一样对接上,管道读取流就可以读取管道写入流写入的数据。 注意:需要加入多线程技术,因为单线程,先执行read,会发生死锁,因为read方法是阻塞式的,没有数据...
  • u013160069
  • u013160069
  • 2014-01-11 17:43
  • 607

java--io流-打印流,序列流,操作对象,管道流,RandomAccessFile,操作字节数组

打印流: 该流提供了打印方法,可以将各种数据类型的数据都原样打印。 字节打印流: PrintStream 构造函数可以接收的参数类型: 1,file对象。File 2,字符串路径。Stri...
  • ccc20134
  • ccc20134
  • 2014-04-01 16:35
  • 356

黑马程序员_Java基础_IO流_打印流,合并流,分割文件,对象持久化,管道流...其他常用流

一,IO的打印流:PrintStream和PrintWriter         public PrintWriter(OutputStream out,boolean autoFlus...
  • u013432047
  • u013432047
  • 2014-05-20 23:26
  • 681

JAVA之旅(三十)——打印流PrintWriter,合并流,切割文件并且合并,对象的序列化Serializable,管道流,RandomAccessFile,IO其他类,字符编码

JAVA之旅(三十)——打印流PrintWriter,合并流,切割文件并且合并,对象的序列化Serializable,管道流,RandomAccessFile,IO其他类,字符编码 三十篇了,又是...
  • qq_26787115
  • qq_26787115
  • 2016-07-17 20:29
  • 3809

黑马程序员——Java基础---IO(二)---对象流、管道流、RandomAccessFile、数据流、数组流、字符编码

-----------android培训、java培训、java学习型技术博客、期待与您交流!------------ 学习笔记——IO流——对象流、管道流、RandomAccessFile、数据流、...
  • tian_wang
  • tian_wang
  • 2015-03-18 17:49
  • 345

JAVA基础 day23 IO流的其他类 (对象的序列化 管道流 RandomAccessFile类(随机读取文件) DateStream(操作基本数据类型的流) 操作数组的流 )字符编码问题

IO流其他类对象的序列化 序列化:把Java对象转换为字节序列的过程。 反序列化:把字节序列恢复为Java对象的过程用途:把对象的字节序列永久的保存到硬盘上,通常存在文件中。 ...
  • c99463904
  • c99463904
  • 2016-10-25 23:01
  • 245
    个人资料
    • 访问:41084次
    • 积分:774
    • 等级:
    • 排名:千里之外
    • 原创:19篇
    • 转载:112篇
    • 译文:0篇
    • 评论:3条
    文章分类
    最新评论