写作目的

自学Java,Java中流的概念比较复杂,故专门作一整理。期望开始学习的童鞋,看完本文后对Java流有一个大致的认识。主要分三个小篇:

一、概述、输入/输出字节流

二、输入/输出字符流、装饰者模式与处理流

三、其他

本文首先大致介绍以下流的概念和分类,然后介绍字节流的接口,最后介绍一些三种常用的字节流,并举例说明它们的用法。

一、什么是流

首先,给一个图,给大家一个感性的认识。大家至少接触过面向对象语言,在面向对象语言中讲到输入输出(I/O)时,一般都是流。那什么是流呢?你能准确描述一下吗?其实我也不能准确描述描述,下面是我的理解。首先说说IO,IO就是将数据从一个地方搬运到另一个地方,如从一个文件运到内存中,从一台机器运到另一台机器。再来说说流,流就是隐藏这一搬运细节的一个对象(或者说将搬运细节封装起来了)。如上图所示,流对象就像桥一样,连接源数据和目标存放位置,我们程序员呢,什么都不用管,只要将源数据按照流对象规定的格式存到流对象中或从流对象读出来。

二、Java中的流

每学一门编程语言,I/O总是很头疼的一块,虽然我一直用C++写代码,但对C++的流我也没有搞懂。像控制结构、基本数据类型、运算类型等等一般都是相同的,但是流在不同的语言中会有很大差别。因为是自学,所以就把它弄清楚一些。JDK本身提供了丰富的流类型。我们首先用思维导图的方式来将这些类整理一下:

是不是很壮观,先大体上说下Java流的分类:

  • 按流向分,可分为输入流和输出流(输入/输出是针对CPU而言的);

  • 按处理数据的类型,可字节流和字符流(一般字节流就够用了,涉及到文本编码,尤其是非ASCII编码的会用到字符流)。在此,要强调的一点:磁盘上存储的所有数据都是面向字节的,字符只存在程序(或者说内存)中。

  • 按功能分,可分为节点流和处理流。节点流提供基本功能,处理流提供扩展功能,增加性能。

  所有这些类中,最重要的就是InputStream和OutputStream,接着是Reader和Writer。首先来详细介绍以下InputStream的接口。

2.1 InputStream类提供的接口

接口一、从流中读入一个字节的数据

  上面这个方法是InputStream唯一的抽象方法,子类必须实现这一方法,其功能是读入一个字节的数据。不同的输入流(有不同的数据源),读入的方式当然是不一样的,接下来要介绍的几个接口都依赖于这一接口。此接口返回值有两种可能:(1) 读到字节的值; (2) -1表示已经读到流的结束。

接口二、从流中读入若干个字节

  这个函数是从流中读入若干字节到缓存数组b[]中,返回值也有两种情况:

  (1) 实际读到字节数组b中的字节数(可能<b.length);

  (2) -1,已经到流的结尾啦,没有字节可读了!

  一般而言,上述两个函数是我们在使用输入流时,最常用的两个函数。另外,JDK还给我们提供了另一个更为灵活的读入若干字节的接口:

  这个接口与上一个接口的功能是类似的,只是增加了off和len两个参数,使用户可以指定读入字节的起始位置和长度。如果len + off > b.length,会抛出一个IndexOutofBoundsException异常。

2.2 OutputStream类提供的接口

  接下来,介绍输出流的接口。OutputStream的接口与InputStream的接口是一一对应的。你有read一个字节,那我就有write一个字节;你有read若干个字节,那我就有write若干个字节。接口如下(不做详细介绍了):

  1. public abstract void write(int b) throws IOException;
  2. public void write(byte b[]) throws IOException;
  3. public void write(byte b[], int off, int len) throws IOException;

2.3 字节流的派生类及作用

2.4 流的使用

下面通过几个实例来看看第3节介绍的三种流的用法。

1. 文件输入流

  1. public static void main(String args[]) throws IOException {
  2. // 定义文件输入流
  3. FileInputStream fis = new FileInputStream("test.txt");
  4.  
  5. // 定义读入缓存字节
  6. byte buf[] = new byte[1024];
  7.  
  8. // 使用read接口读入
  9. fis.read(buf);
  10.  
  11. // 输出读入的字节
  12. System.out.println(new String(buf));
  13. }

【注】这里读入的buf字节数组,将其按系统默认字符集编码转为String字符串,然后输出。若文件的字符集编码与系统默认字符集编码不一致,则需要在构造String指定编码,否则可能出现乱码。

2. 字节数组输入流

  前面已经指出,该流主要用于接收并解析网络数据,在单机上没啥意思。另外,需要配合处理流(如:DataInputStream)一起使用,在这里我们通过一个简单的例子来演示一下。

  1. public static void main(String args[]) throws IOException {
  2. // 定义输入缓冲区,这部分内容通常由网络传输过来的。
  3. String sBuf = new String("ByteArrayInputStream Test.");
  4. byte buf[] = sBuf.getBytes();
  5.  
  6. // 定义输入字节数组流
  7. ByteArrayInputStream bais = new ByteArrayInputStream(buf);
  8.  
  9. // 读入其中的8个字节并输出
  10. byte[] obuf = new byte[8];
  11. bais.read(obuf);
  12. System.out.println(new String(obuf));
  13.  
  14. // 再次强调:上述三行代码仅仅演示,一般字节数组流不单独使用。
  15. }

3. 管道流

  配合使用,最好在线程中使用,便于线程的通信。为了演示,首先派生两个线程类,如下:

  1. //实现两个线程类
  2. class ThreadRead extends Thread {
  3.  
  4. private PipedInputStream mPis = null;
  5.  
  6. public ThreadRead(PipedInputStream pis) {
  7. mPis = pis;
  8. }
  9.  
  10. // 读取管道流内容并输出
  11. public void run() {
  12. byte[] buf = new byte[100];
  13. try {
  14. mPis.read(buf);
  15. } catch (IOException e) {
  16. // TODO Auto-generated catch block
  17. e.printStackTrace();
  18. }
  19. System.out.println(new String(buf));
  20. }
  21. }
  22.  
  23. class ThreadWrite extends Thread {
  24.  
  25. PipedOutputStream mPos = null;
  26.  
  27. public ThreadWrite(PipedOutputStream pos) {
  28. mPos = pos;
  29. }
  30.  
  31. public void run() {
  32. String s = new String("你好!PipedOutputStream.");
  33. try { mPos.write(s.getBytes());
  34. } catch (IOException e) {
  35. // TODO Auto-generated catch block
  36. e.printStackTrace();
  37. }
  38. }
  39. }
  1. 主函数如下:
  1. public class PipedStreamDemo01 {

  1. public static void main(String args[]) {
  2. PipedOutputStream pos = new PipedOutputStream();
  3. PipedInputStream pis = null;
  4. try {
  5. pis = new PipedInputStream(pos);
  6. } catch (IOException e) {
  7. // TODO Auto-generated catch block
  8. e.printStackTrace();
  9. }
  10. Thread th1 = new ThreadRead(pis);
  11. Thread th2 = new ThreadWrite(pos);
  12. th2.start();
  13. th1.start();
  14. }

三、小结

  到此,字节流大致介绍完毕。

Java I/O学习(一)的更多相关文章

  1. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

  2. 一位资深程序员大牛给予Java初学者的学习路线建议

    java学习这一部分其实也算是今天的重点,这一部分用来回答很多群里的朋友所问过的问题,那就是我你是如何学习Java的,能不能给点建议?今天我是打算来点干货,因此咱们就不说一些学习方法和技巧了,直接来谈 ...

  3. java并发编程学习: ThreadLocal使用及原理

    多线程应用中,如果希望一个变量隔离在某个线程内,即:该变量只能由某个线程本身可见,其它线程无法访问,那么ThreadLocal可以很方便的帮你做到这一点. 先来看一下示例: package yjmyz ...

  4. 回答阿里社招面试如何准备,顺便谈谈对于Java程序猿学习当中各个阶段的建议

    引言 其实本来真的没打算写这篇文章,主要是LZ得记忆力不是很好,不像一些记忆力强的人,面试完以后,几乎能把自己和面试官的对话都给记下来.LZ自己当初面试完以后,除了记住一些聊过的知识点以外,具体的内容 ...

  5. Java程序员学习之路

    1. Java语言基础 谈到Java语 言基础学习的书籍,大家肯定会推荐Bruce Eckel的<Thinking in Java>.它是一本写的相当深刻的技术书籍,Java语言基础部分基 ...

  6. 老鸟谈谈JAVA EE的学习

    老鸟谈谈JAVA EE的学习 因为出差和项目的原因,有将近一个月的时间没有更新博客了,今天终于得闲,和兄弟们分享一下JAVA EE的学习心得.书中带过,直入主题,下面我们首先看看什么是JAVA EE. ...

  7. Java虚拟机JVM学习07 类的卸载机制

    Java虚拟机JVM学习07 类的卸载机制 类的生命周期 当Sample类被加载.连接和初始化后,它的生命周期就开始了. 当代表Sample类的Class对象不再被引用,即不可触及时,Class对象就 ...

  8. Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论

    Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...

  9. Java虚拟机JVM学习05 类加载器的父委托机制

    Java虚拟机JVM学习05 类加载器的父委托机制 类加载器 类加载器用来把类加载到Java虚拟机中. 类加载器的类型 有两种类型的类加载器: 1.JVM自带的加载器: 根类加载器(Bootstrap ...

  10. Java虚拟机JVM学习04 类的初始化

    Java虚拟机JVM学习04 类的初始化 类的初始化 在初始化阶段,Java虚拟机执行类的初始化语句,为类的静态变量赋予初始值. 在程序中,静态变量的初始化有两种途径: 1.在静态变量的声明处进行初始 ...

随机推荐

  1. iOS app提交审核 11.13条款问题

    今年开年到现在.提交app应用一直招拒,这个问题我想不明白,感觉就是一个坑.所以贴出来给大家看看. 发件人 Apple11.13 - Apps that link to external mechan ...

  2. 常用JS正则表达式收集

    1.去掉字符串前后空格,不会修改原有字符串,返回新串.str.replace(/(^\s*)|(\s*$)/g,'');

  3. ES6的编码风格

    编程风格 [转自http://es6.ruanyifeng.com/#docs/style] 块级作用域 字符串 解构赋值 对象 数组 函数 Map结构 Class 模块 ESLint的使用 本章探讨 ...

  4. 09.25日记(2014年9月25日23:22:06)用java这么多年面向对象我真的懂了吗,测试先行理念会玩吗

    二胡 (1)应该找些书来看看,工作N年并不代表就有N年的工作经验. (2)DiaTransit02,DiaDept02,DiaAirport02,DiaHighway02.都具有x,y属性为何不设计一 ...

  5. caffe源码阅读(2)-Layer

    神经网络是由层组成的,深度神经网络就是层数多了.layer对应神经网络的层.数据以Blob的形式,在不同的layer之间流动.caffe定义的神经网络已protobuf形式定义.例如: layer { ...

  6. z-index使用以及失效的处理方法

    1.一般z-index的使用是在有两个重叠的标签,在一定的情况下控制其中一个在另一个的上方出现. 2.z-index值越大就越是在上层.z-index:9999:z-index元素的position属 ...

  7. 解析sql中的表名

    最近的项目需求中需要解析sql得表名,由于只需要表名我觉得应该用相对粗暴一点的方式来解析 初步思路: 1.转义字符:去除两个引号连在一起的 2.字符串: 去除所有被引号包裹的 3.括号:识别括号处理 ...

  8. ImageList半透明,Alpha通道bug处理。

    由于ImageList的先天障碍,对alpha通道支持不好.虽然到xp有所改善,但瑕疵依然存在. 通过reflactor发现ImageList通过windows api来进行读写的.写入数据时会对原始 ...

  9. bzoj2427: [HAOI2010]软件安装

    Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和 ...

  10. OC修饰词 - 内存管理

    <招聘一个靠谱的 iOS>—参考答案(上) 说明:面试题来源是微博@我就叫Sunny怎么了的这篇博文:<招聘一个靠谱的 iOS>,其中共55题,除第一题为纠错题外,其他54道均 ...