博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java IO 之 介质流
阅读量:6202 次
发布时间:2019-06-21

本文共 5863 字,大约阅读时间需要 19 分钟。

hot3.png

自己工作虽有将近三年了,也算得上是一个程序老手了,但对IO这块一直一知半解,以至于每次写IO相关的代码时,总不能随心所欲的写出自己想要的代码,每次都要百度别人的代码来借鉴。究其原因还是因为对IO这块了解的不够深入。真是如鱼刺在喉,不咽不快,这次一定要把IO这块知识咽下去。

其实对 IO 这块知识之前也有意学习过,但每次都不得要领,学了忘,用的时候再去学,一直无法理解 IO 的精髓,所以也就无法真正的领略IO了。这次学习IO总算没了之前学习的时候云里雾里的感觉。或许有些知识,真的需要时间的积累才能够理解罢!IO这块知识真的挺难理解的,很难初次学习就能对这块知识系统的理解,甚至两次、三次我们会越学越糊涂,但不要放弃,多多接触,多多看相关文章,总有那么一个时刻你会发现柳暗花明了,IO也不过如此了。

此篇文章内容多为我个人本次学习对IO的理解,可能不会太系统和太完善,不喜勿喷哦。

建议读此篇文章前,先读这篇文章:(要都三遍哦!!!)

读了上面的文章,你应该已经知道,Java IO 中一般包含两个部分:

  1. java.io包中堵塞型 IO

  2. java.nio包中的非堵塞型 IO,通常称为New IO

本篇文章主要介绍java.io包中堵塞型 IO

打开你的java.io包你可以看到Java的IO包含大量的类和接口(JDK1.6中包含83个类或者接口),如此众多的类和接口似乎无从下手。下面就将IO简单地分类。

Java的IO主要包含三个部分:

  1. 流式部分 -- IO 的主体部分

  2. 非流式部分 -- 主要包含一些辅助流式部分的类,如:File类、RandomAccessFile类和FileDescriptor等类

  3. 文件读取部分的与安全相关的类,如:SerializablePermission类。以及与本地操作系统相关的文件系统的类,如:FileSystem类和Win32FileSystem类和WinNTFileSystem类

其中“流式部分”又可以概括为:两个对应一个桥梁。两个对应指:

  1. 字节流(Byte Stream)和字符流(Char Stream)的对应

  2. 输入和输出的对应

一个桥梁指:从字节流到字符流的桥梁。对应于输入和输出为InputStreamReader和OutputStreamWriter。

在流的具体类中又可以具体分为:

  1. 介质流(Media Stream或者称为原始流Raw Stream)

    -- 主要指一些基本的流,他们主要负责从具体的介质上读取数据。

    如:从文件、内存缓冲区(Byte数组、Char数组、StringBuffer对象)等,读取数据;

  2. 过滤流(Filter Stream)

    -- 主要指所有FilterInputStream/FilterOutputStream和FilterReader/FilterWriter的子类,主要是对其包装的类进行某些特定的处理,如:缓存等。

    -- 无法单独使用,必须配合其他的一些输入输出流使用,被包装后的对象具有过滤流提供的功能如:被BufferedInputStream包装后对象具有缓存的功能,被DataInputStream包装后的对象具有读取基本数据类型的功能

上面这段的内容来自之前提到的文章,个人觉得总结的十分经典,就直接”拿来主义”了,建议上面的内容也都三遍哦。

实践是检验理论的唯一标准,编码更是如此,上面提到的模糊的概念你可能不甚理解,下面我们结合具体场景来看一下。以 Java IO 中的 字节流 中的 输入流 来具体讲解一下。

我们先来看一张图(网上找来的一张图,经测试发现并不存在ByteArrayReader这个类,图中已标红),这是java io 比较基本的一些处理流,你现在只需要看IO流-->字节流-->InputStream的那部分,结合上面的内容你应该至少知道哪些是介质流?哪些是过滤流?介质流是用来干嘛的?输入流是用来干嘛的?(不知道的话回到上面再读一遍吧)

152256_85Qr_2374253.jpg

是的,除了 ObjectInputStream 和 FilterInputStream 下的三个类,其余全是介质流,前面说过了,介质流是主要负责从具体的“介质”上读取数据的,其中“介质”可以是文件、图片、Byte数组、String对象,StringBuffer对象等。从不同“介质”上读取数据,采用的流也不相同。例如:从byte数组中读取数据到流,很显然我们知道应该用 ByteArrayInputStream。同理,从文件中读取数据,我们应该用FileInputStream。

下面我们结合上面的图,依次展示和讲解一下这些流的具体用法。

介质流

  • ByteArrayInputStream。

    我们读取一个byte数组,然后依次打印数组中的成员对应的ascii码。很显然,从byte数组中读取数据,我们应该用ByteArrayInputStream,将数组读取到流中以后,我们就能够以操作流的方式来操作byte数组了。

byte[] b = new byte[] {'j', 'a', 'v', 'a', 'i', 'o'};ByteArrayInputStream bis = new ByteArrayInputStream(b);int c;// read()方法返回int类型0-255之间的数字。读取流结束返回-1// 想想为什么返回 0-255?while ((c = bis.read()) != -1) {    System.out.println(c);}

        我们知道,计算机的最小存储单位是字节(byte),因此任何类型的数据(图片,文件,英文字符,汉字)都可以用连续的         字节(byte)来表示。任意一个英文字符,用一个字节(byte)即可表示,汉字需要两个字节(byte),一个图片或文件可以            由若干个连续的字节(byte)表示。在计算机中一个字节(byte)可以存储8位二进制数。换算为十进制,范围就是0-255

  • StringBufferInputStream。

    其用法和ByteArrayInputStream类似,不再演示。StringBufferInputStream已经被@Deprecated,原因是StringBufferInputStream不应该属于字节流,推荐使用StringReader。

  • SequenceInputStream 。

    将2个或者多个InputStream 对象转变为一个InputStream,和你想象的一样,SequenceInputStream的构造函数中可以传入两个InputStream,也可以传入一个Enumeration集合

byte[] java = new byte[]{'j', 'a', 'v', 'a'};byte[] io = new byte[]{'i', 'o'};ByteArrayInputStream bais1 = new ByteArrayInputStream(java);ByteArrayInputStream bais2 = new ByteArrayInputStream(io);SequenceInputStream sis = new SequenceInputStream(bais1, bais2);int t;while ((t = sis.read()) != -1) {    System.out.println(t);}

  • PipedInputStream 

    一般和PipedOutputStream配合使用,读取从对应PipedOutputStream写入的数据。在流中实现了管道的概念。

PipedOutputStream pos = new PipedOutputStream();PipedInputStream pis = new PipedInputStream();pis.connect(pos);String pipedStr = "Hi, PipedInputStream and PipedOutputStream";// 管道输出流写出字节pos.write(pipedStr.getBytes());int t;// 相应管道输入流进行读取while ((t = pis.read()) != -1) {    System.out.print((char)t);}pis.close();pos.close();

        这是管道流最基本的应用。利用管道流还可以实现线程间的通信。我们做这样一个应用:启动两个线程,一个线程负责           发送数据,一个线程负责接收数据。

// Sender.java 文件public class Sender implements Runnable {    PipedOutputStream out = new PipedOutputStream();      /**     * PipedOutputStream 和 PipedInputStream 要配对使用,双方进行连接后,write的数据才能被read到     * 故在此返回 PipedOutputStream 对象     */    public PipedOutputStream getPipedOutputStream() {        return out;    }    @Override    public void run() {        String str = "hi, pipedStream in thread";        try {            for (byte b : str.getBytes()) {                out.write((char)b);                System.out.println("send --> " + (char)b);                Thread.sleep(500);            }            out.close();            } catch (Exception e) {                e.printStackTrace();            }	}}
// Receiver.javapublic class Receiver implements Runnable {		PipedInputStream in = new PipedInputStream();		public PipedInputStream getPipedInputStream() {		return in;	}	@Override	public void run() {		int t;		try {			while ((t = in.read()) != -1) {				System.out.println("receive --> " + (char)t);				Thread.sleep(300);			}		} catch (Exception e) {			e.printStackTrace();		}	}}
// 运行此main方法可以看出运行结果public class PipedStream4Thread {	public static void main(String[] args) throws Exception {		Sender sender = new Sender();		Receiver receiver = new Receiver();		PipedOutputStream out = sender.getPipedOutputStream();		PipedInputStream in = receiver.getPipedInputStream();		in.connect(out);				new Thread(sender).start();		new Thread(receiver).start();	}}
  • FileInputStream

    从名称就可以看出,它是用来把文件转换为流的。

public class FileInputStreamTest {	public static void main(String[] args) throws Exception {		// 不指定具体路径是指当前项目跟路径下		FileInputStream fis = new FileInputStream("file");		byte[] buf = new byte[4];		int bLen = buf.length;		int t;		// 想想read(buf, 0, bLen)和read()方法的区别?		while ((t = fis.read(buf, 0, bLen)) != -1) {			// 主意new String(buf, 0, t)一定要带 0,t 参数			// 自己想想为什么吧 			System.out.print(new String(buf, 0, t));		}		fis.close();	}		/**	 * 这里使用的是read(byte b[], int off, int len)方法进行文件字节读取,没有使用read()方法。	 * 	 * read()方法每读取一个字节就要进行一次本地磁盘IO	 * read(byte b[], int off, int len)方法每次从本地磁盘文件中读取bLen个字节。有效的减少了程序访问本地磁盘的次数,提高了效率,	 * 其中bLen是b[]数组的长度。读取的字节数组会被放入b[]中,放在b[]中第off个位置先后的len个位置中	 * 	 */	}

至此,介质流已经介绍完了,实际应用中我们应该根据从不同介质读取数据,而使用相应的介质流。

下面我们来看过滤流。前面说过,过滤流必须配合其他的一些输入输出流使用,被包装后的对象具有过滤流提供的功能。

转载于:https://my.oschina.net/ironwill/blog/519238

你可能感兴趣的文章
干锅土豆
查看>>
Android底部导航栏
查看>>
cmd的一些参数
查看>>
母爱无疆
查看>>
VC中调用外部程序方式总结
查看>>
Android代码混淆的实践
查看>>
通过本地的SQL Manage sutudio管理windows azure上的SQL Server
查看>>
CodeSmith模板引擎系列一
查看>>
service redis does not support chkconfig的解决办法
查看>>
获取每个磁盘分区的空间使用率
查看>>
移动互联网发展对应用交付器的新要求
查看>>
中国式并购:流动的宏碁
查看>>
Asp.net mvc3.0安装包及帮助文档下载地址~~
查看>>
Java锁细节整理
查看>>
RHEL 5基础篇—系统设置及基本操作
查看>>
Android开发学习笔记:数据存取之Preference浅析
查看>>
教学思路WinForms之 windows服务
查看>>
常用API-Arrays
查看>>
springboot+thymeleaf模板的一个问题,搞了一天才搞定。
查看>>
about rubygems install
查看>>