Java基础:流Stream详解

目录
  • 写在前面
  • 一、"流"概念
  • 二、流的分类
    • 1、按流的方向分为:输入流、输出流
    • 2、按流处理数据的单位分为:字节流、字符流
    • 3、按流的功能分为:节点流(又称低级流)、过滤流(又称高级流、处理流、包装流)
    • 4、字节流与字符流区别
  • 三、流的方法
    • 1、字节流
      • 字节输入流类:FileInputStream、BufferedInputStream和DataInputStream
      • 构造方法:
      • 常用方法:
      • 构造方法:
      • 常用方法:
      • 构造方法:
      • 常用方法:
      • 字节输出流类:FileOutputStream、BufferedOutputStream和DataOutputStream
      • 构造方法:
      • 常用方法:
      • 构造方法:
      • 常用方法:
      • 常用方法:
    • 2、字符流
      • 构造方法:
      • 构造方法:
      • 操作方法:
      • 构造方法:
    • 缓冲流的目的:
  • 4、流相关设计模式
  • 总结

写在前面

从Java 1.0开始,引入java.io包;到Java 1.4再扩展了java.nio包;再到java 1.7又添加了新的流类,使得Java的流机制变得十分强大。

一、"流"概念

James Gosling所著《Java程序设计》中描述Java I/O流模式图如下。Program是中间环节,用于对Source进行处理,然后输出到Dest处。

Java中的"流"就是指把数据从一个对象移动到另一个对象的流动模式的抽象。其实Java的流模式用水流或者电流模型来解释是很容易理解的。

James Gosling的Java流模式图与水流模式图概念映射。数据源(data source)即水库,数据目的地(data destination)就是脸盆,数据(data)就是水,流(stream)实例化就是在管子中流动的水流。

输入流(input stream)就是用水泵从水库中抽出来要到水管中的水,输出流(output stream)经过水龙头将要达到脸盆中的水,计算机内存(memory)就是上图中的水流管道,关闭输入流(close input stream)就是关闭水泵开关,关闭输出流(close output stream)就是关闭关闭水龙头开关。

更进一步说,具体的水库和脸盆分别对应于Java中输入流对象和输出流对象。水流可以分成一粒一粒的水分子,这些水分子映射成计算机二进制位(bit)0/1,其组成的水滴映射成计算机字节流(字节是计算机储存信息的基本单位)。字节流和字符流在物理层面的实现都是比特流,二进制数据流可以认为是字节流,而字符流是遵循unicode编码规则的字节流。因此计算机中的"流"概念实际上就是指字节数据(bytes data)从源对象对按顺序流向目标对象的一种流动形式。

二、流的分类

1、按流的方向分为:输入流、输出流

判断当前流是输入流还是输出流的依据是二进制数据相对于计算机内存的位置,输入流是输入计算机内存是二进制数据,输出流是从计算机内存输出的二进制数据。而计算机程序在运行期间会储存在到计算机内存中,因此总的来说就是数据的来源、取向是相对程序而言的。比如键盘键入数据属于输入流,内存数据持久化到磁盘中属于输出流。

说明:本图片取自互联网,纠正补充为流的来源有网络连接、内存块、磁盘(文件)、键盘等;流的去向也基本是这些。

2、按流处理数据的单位分为:字节流、字符流

从物理层面来看,流中数据都是二进制比特流。而计算机中储存信息的基本单位是字节(Byte)。因此,可以认为计算机中信息传输在底层是靠字节流来实现的。字符流只是通过不同的字符编码方式,对字节流的封装,即字符流的实现还是得依靠字节流。

3、按流的功能分为:节点流(又称低级流)、过滤流(又称高级流、处理流、包装流)

节点流(Node Stream)是流管道两端直接连接data source和data destination上的,即为取放数据的真实载体,在流通道本身不对数据做任何加工,因而也被称为低级流。

节点流从一个特定的数据源读写数据。即节点流是直接操作文件,网络等的流,例如FileInputStream和FileOutputStream,他们直接从文件中读取或往文件中写入字节流。

“连接”在已存在的流(节点流或处理流)之上通过对数据的处理为程序提供更为强大的读写功能。过滤流是使用一个已经存在的输入流或输出流连接创建的,过滤流就是对节点流进行一系列的包装。例如BufferedInputStream和BufferedOutputStream,使用已经存在的节点流来构造,提供带缓冲的读写,提高了读写的效率,以及DataInputStream和DataOutputStream,使用已经存在的节点流来构造,提供了读写Java中的基本数据类型的功能。他们都属于过滤流。

public static void main(String[] args) throws IOException {
        // 节点流FileOutputStream直接以A.txt作为数据源操作
        FileOutputStream fileOutputStream = new FileOutputStream("A.txt");
        // 过滤流BufferedOutputStream进一步装饰节点流,提供缓冲写
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
                fileOutputStream);
        // 过滤流DataOutputStream进一步装饰过滤流,使其提供基本数据类型的写
        DataOutputStream out = new DataOutputStream(bufferedOutputStream);
        out.writeInt(3);
        out.writeBoolean(true);
        out.flush();
        out.close();
        // 此处输入节点流,过滤流正好跟上边输出对应,读者可举一反三
        DataInputStream in = new DataInputStream(new BufferedInputStream(
                new FileInputStream("A.txt")));
        System.out.println(in.readInt());
        System.out.println(in.readBoolean());
        in.close();
}

理解:

  • FileOutputStream是根据二进制010101一个一个字节处理
  • BufferedOutputStream是对字节封装成buffered,以缓冲区处理
  • DataOutputStream是以字符串形式,类似(“hello”)处理。

4、字节流与字符流区别

  • 字节流默认是不带缓冲区的,而字符流默认是带缓冲区的。
  • 字节流是底层数据流,是数据有意义的最小单位。字符流是字节流的包装,底层实现是字节流。
  • 字节流读取的时候,读到一个字节就返回一个字节;字符流使用了字节流读到一个或多个字节(中文对应的字节数是两个,在UTF-8码表中是3个字节)时。先去查指定的编码表,将查到的字符返回。
  • 字节流可以处理所有类型数据,如:图片,MP3,AVI视频文件,而字符流只能处理字符数据。只要是处理纯文本数据,就要优先考虑使用字符流,除此之外都用字节流。文本文件可以用字节流来实现,当然使用字符流速度会更快。

三、流的方法

1、字节流

字节输入流类:FileInputStream、BufferedInputStream和DataInputStream

FileInputStream:此类用于从本地文件系统中读取文件内容。

构造方法:

  • FileInputStream(File file):打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的File对象file指定。
  • FileInputStream(String name):打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的路径名name指定。

常用方法:

  • int available():返回下一次对此输入流调用的方法不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。
  • void close():关闭此文件输入流并释放与该流关联的所有系统资源。

BufferedInputStream此类本身带有一个缓冲区,在读取数据时,先放到缓冲区中,可以减少对数据源的访问,提高运行的效率。

构造方法:

  • BufferedInputStream(InputStream in):创建一个BufferedInputStream并保存其参数,即输入流in,以便将来使用。
  • BufferedInputStream(InputStream in,int size):创建一个具有指定缓冲区大小的BufferedInputStream并保存其参数,即输入流in,以便将来使用。

常用方法:

  • int available():返回下一次对此输入流调用的方法不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。
  • void close():关闭此输入流并释放与该流关联的所有系统资源。
  • int read():从输入流中读取数据的下一个字节。
  • int read(byte[] b,int off,int len):从此字节输入流中给定偏移量处开始将各字节读取到指定的byte数组中。

DataInputStream:该类提供一些基于多字节读取方法,从而可以读取基本数据类型的数据。

构造方法:

  • DataInputStream(InputStream in):使用指定的底层InputStream创建一个DataInputStream。

常用方法:

  • int read(byte[] b):从包含的输入流中读取一定数量的字节,并将它们存储到缓冲区数组b中。
  • int read(byte[] b,int off,int len):从包含的输入流中将最多len个字节读入一个byte数组中。

字节输出流类:FileOutputStream、BufferedOutputStream和DataOutputStream

FileOutputStream:此类用于从本地文件系统的文件中写入数据。

构造方法:

  • FileOutputStream(File file):创建一个向指定File对象表示的文件中写入数据的文件输出流。FileOutputStream(String name):创建一个向具有指定名称的文件中写入数据的输出文件流。

常用方法:

  • void close():关闭此文件输出流并释放与此流有关的所有系统资源。
  • FileDescriptor getFD():返回与此流有关的文件描述符。
  • void write(byte[] b):将b.length个字节从指定byte数组写入此文件输出流中。
  • void write(byte[] b,int off,int len):将指定byte数组中从偏移量off开始的len个字节写入此文件输出流。
  • void write(int b):将指定字节写入此文件输出流。

BufferedOutputStream:此类本身带有一个缓冲区,在写入数据时,先放到缓冲区中,实现缓冲的数据流。

构造方法:

  • BufferedOutputStream(OutputStream out):创建一个新的缓冲输出流,来将数据写入指定的底层输入流。
  • BufferedOutputStream(OutputStream out,int size):创建一个新的缓冲输出流,来将具有指定缓冲区大小的数据写入指定的底层输出流。

常用方法:

  • void flush():刷新此缓冲的输出流。
  • void write(byte[] b,int off,int len):将指定byte数组中从偏移量off开始的len个字节写入此缓冲的输出流。
  • void write(int b):将指定的字节写入此缓冲的输出流。

DataOutputStream(OutputStream out):创建一个新的数据输出流,将数据写入指定基础输出流。

常用方法:

  • void flush():清空此数据输出流。
  • int size():返回计数器written的当前值,即到目前为止写入此数据输出流的字节数。
  • void write(byte[] b,int off,int len):将指定byte数组中从偏移量off开始的len个字节写入基础输出流。
  • void write(int b):将指定字节(参数b的八个低位)写入基础输出流。

2、字符流

FileReader:用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的

构造方法:

FileReader(File file):在给定从中读取数据的File的情况下创建一个新的FileReader。FileReader(String fileName):在给定从中读取数据的文件名的情况下创建一个新的FileReader。

BufferedReader类是Reader类的子类,为Reader对象添加字符缓冲器,为数据输入分配内存存储空间,存取数据更为有效。

构造方法:

  • BufferedReader(Reader in):创建一个使用默认大小输入缓冲区的缓冲字符输入流。
  • BufferedReader(Reader in,int sz):创建一个使用指定大小输入缓冲区的缓冲字符输入流。

操作方法:

  • void close():关闭该流并释放与之关联的所有资源。
  • void mark(int readAheadLimit):标记流中的当前为止。
  • boolean markSupported();判断此流是否支持mark()操作。
  • int read():读取单个字符。
  • int read(char[] cbuf,int off,int len):将字符读入数组的某一部分。
  • String readLine():读取一个文本行。
  • boolean ready():判断此流是否已准备好被读取。
  • void reset():将流重置到最新的标记。
  • long skip(long n):跳过字符。

FileWriter:用来写入字符文件的便捷类,可用于写入字符流。

构造方法:

FileWriter(File file):根据给定的File对象构造一个FileWriter对象。

FileWriter(String filename):根据给定的文件名构造一个FileWriter对象。

BufferedWriter: 将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

缓冲流的目的:

操作流的时候,习惯定义一个byte/char数组。

int read(): 每次都从磁盘文件中读取一个字节。 直接操作磁盘文件性能极低。

解决方案:定义一个数组作为缓冲区。

byte[] buffer = new byte[1024];该数组其实就是一个缓冲区。

一次性从磁盘文件中读取1024个字节。如此以来,操作磁盘文件的次数少了,性能得以提升。提供的默认缓存区大小是8192(1024*8),我们一般不用修改大小

public class BufferStreamDemo {
    public static void main(String[] args) throws Exception {
        File file = new File("file/aaa.txt");
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
        out.write("中国".getBytes());
        out.close();
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
        byte[] buffer = new byte[1024];
        int len = -1;
        while((len = in.read(buffer)) != -1){
            System.out.println(new String(buffer, 0, len));
        }
        in.close();
    }
}
public class BufferCharacterDemo {
    public static void main(String[] args) throws Exception {
        File file = new File("file/aaa.txt");
        BufferedWriter in = new BufferedWriter(new FileWriter(file,true));
        in.newLine();//用来换行等同于‘\n'
        in.write("美国");
        in.newLine();
        in.write("马来西亚");
        in.close();
        BufferedReader out = new BufferedReader(new FileReader(file));
        String line = null;
        //按行读取
        while((line = out.readLine()) != null){
            System.out.println(line);
        }
        out.close();
    }
}

4、流相关设计模式

处理流/包装流(相对于节点流更高级) 装饰设计模式/包装模式:

  • 隐藏了底层的节点流的差异,并对外提供了更方便的输入/输出功能,让我们只关心高级流的操作.
  • 使用处理流包装了节点流,程序直接操作处理流,让节点流与底层的设备做IO操作.
  • 只需要关闭处理流即可.

参考:https://blog.csdn.net/dreamzuora/article/details/79691702

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • Java常用数据流全面大梳理

    目录 缓冲流 转换流 标准输入输出流 打印流 数据流 对象流 随机存取文件流 Java NIO 缓冲流 为了提高数据读写的速度,Java API提供了带缓冲功能的流类,在使用这些流类时,会创建一个内部缓冲区数组,缺省使用8192个字节(8Kb)的缓冲区. 缓冲流要"套接"在相应的节点流之上,根据数据操作单位可以把缓冲流分为: BufferedInputStream 和 BufferedOutputStream BufferedReader 和 BufferedWriter 当读取数据时

  • Java关于JDK1.8新特性的Stream流

    目录 Java 的Stream流 一.定义 二.操作的特征 三.代码示例 1.生成流 2.forEach 迭代 3.limit方法用于获取指定数量的流 4.map 5.sorted 6.并行(parallel)程序 7.Collectors 8.转化(将枚举类转成map) Java 的Stream流 一.定义 JDK1.8 中增加了Stream流,Stream流是一个来自数据源的元素队列并支持聚合操作.元素是特定类型的对象,形成一个队列,Java中的Stream并不会存储元素,而是按需计算数据源

  • Java I/O流实例之简历替换

    目录 学习内容 内容管理 java文件I/O实例----生成报表 总结 学习内容 Java I/O 项目案例 内容管理 java文件I/O实例----生成报表 我们之前学习了两个重要的模块,一个就是Java I/O 另外一个就是java的界面编程,界面编程我们已经实践过了,但是I/O流还没有实践过呢,所以接下来将做一个小项目就是打印报表 需求描述 假设有一个简历模板文件,比如resume.template, 文件内容如下 我的名字是(name) 我毕业院校是(schoolName) 我的所学专业

  • Java深入浅出说流的使用

    目录 一.File类的使用 A.常用构造器 B.路径分隔符 C.常用方法 二.流的分类及其体系 输入.输出的标准化过程 1.输入过程 2.输出过程 三.流的详细介绍 1.字节流和字符流 2.节点流和处理流(重点) 3.其他流 1.标准的输入.输出流 对象流 (重点) 对象流的使用 Person类 对象的序列化机制 随机存取文件流(了解) Java中的NIO 一.File类的使用 1.File类的一个对象,代表一个文件或一个文件目录(俗称:文件夹) 2.File了声明在java.io包下 3.Fi

  • Java 数据流之Broadcast State

    一.BroadcastState 的介绍 广播状态(Broadcast State)是 Operator State 的一种特殊类型.如果我们需要将配置 .规则等低吞吐事件流广播到下游所有 Task 时,就可以使用 BroadcastState.下游的 Task 接收这些配置.规则并保存为 BroadcastState,所有Task 中的状态保持一致,作用于另一个数据流的计算中. 简单理解:一个低吞吐量流包含一组规则,我们想对来自另一个流的所有元素基于此规则进行评估. 场景:动态更新计算规则.

  • Java基础:流Stream详解

    目录 写在前面 一."流"概念 二.流的分类 1.按流的方向分为:输入流.输出流 2.按流处理数据的单位分为:字节流.字符流 3.按流的功能分为:节点流(又称低级流).过滤流(又称高级流.处理流.包装流) 4.字节流与字符流区别 三.流的方法 1.字节流 字节输入流类:FileInputStream.BufferedInputStream和DataInputStream 构造方法: 常用方法: 构造方法: 常用方法: 构造方法: 常用方法: 字节输出流类:FileOutputStrea

  • Java基础 Servlet监听器详解

    Java基础 Servlet监听器详解 1 概念:Servlet监听器,用来监听web容器的一些对象状态的变化,主要是ServletContext.HttpSession.HttpServletRequestl三类对象状态.Servlet的监听器 2  Servlet2.4和JSP2.0规范中一共定义了有八个接口类和六种事件. 3 web.xml中定义Servlet的url-pattern时如果url-pattern的值的"/",则说明该Servlet是该项目的默认Servlet,当请

  • Java 基础之内部类详解及实例

     Java 基础之内部类详解及实例 内部类不是很好理解,但说白了其实也就是一个类中还包含着另外一个类 如同一个人是由大脑.肢体.器官等身体结果组成,而内部类相当于其中的某个器官之一,例如心脏:它也有自己的属性和行为(血液.跳动) 显然,此处不能单方面用属性或者方法表示一个心脏,而需要一个类 而心脏又在人体当中,正如同是内部类在外部内当中  实例1:内部类的基本结构 //外部类 class Out { private int age = 12; //内部类 class In { public vo

  • Java基础之Maven详解

    一.Maven环境的搭建 1. 为什么要学习Maven? 2.  Maven项目架构管理工具 3.  下载安装Maven 下载完成后解压 4.  配置环境变量 在我们的系统环境变量中 配置如下配置: - M2_HOME maven目录下的bin目录 - MAVEN_HOME maven的目录 - 在系统的path中配置 %MAVEN_HOME%\bin 测试Maven是否安装完毕,必须保证配置完成 5. 阿里云镜像配置 <mirror> <id>nexus-aliyun</i

  • java基础之方法详解

    一.什么是方法 Java方法是语句的集合,他们在一起执行一个功能. 1.方法是解决一类问题的步骤的有序组合 2.方法包含于类或对对象中 3.方法在程序中被创建,在其他地方被应用 设计方法的原则:方法的本意是功能块,就是实现某个功能的语句块的结合.我们设计方法的时候,最好保持方法的原子性,就是一个方法只完成一个功能,这样利于我们后期的扩展. 当然只读文字不能完全理解,下面的代码一定要自己一个个敲,仔细品味: //类 public class Demo01 { //mian方法,可理解为系统自定义的

  • Java基础之StringBuffer详解

    一.前言 StringBuffer是可变长的字符串 1.append 追加 2.delete 删除 3.insert 插入 4.reverse 反转 二.用法 String str1 = "let there "; StringBuffer sb = new StringBuffer(str1); //根据str1创建一个StringBuffer对象 sb.append("be light"); //在最后追加 System.out.println(sb); sb.

  • Java基础之数组详解

    前言 我们了解数组这个概念之前,我们先思考下面几个问题. 如果我们需要两个数据,那么直接创建两个变量即可 int a; int b; 如果需要五个数据,那么可以创建五个变量 int a; int b; int c; int d; int f; 但如果我们需要100个甚至是1万个数据,那么我们创一万个变量?显然这是不现实的.这个时候就需要我们的数组来起作用!帮我们"批量"创建变量. 由上可以得出:数组的本质就是让我们能"批量"创建相同类型的变量! 一.数组的概念 数组

  • Java基础之TreeMap详解

    一.写在前面 TreeMap的底层数据结构是红黑树,且TreeMap可以实现集合元素的排序. 所以TreeMap的源码需要实现: 1.红黑树的数据结构,以及红黑树的节点插入,删除,以及红黑树的自平衡操作,如左旋,右旋,以及节点变色 2.红黑树需要支持按照指定的比较器进行排序,或者进行自然排序. 二.定义 public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Clo

  • Java基础之反射详解

    前言 反射是我们框架的灵魂,反射也是我们框架的一个底层基石,没有反射也就没有框架,如果我们学好了反射,对我们阅读框架底层是有很大班助的--阿俊.有些文章上来就讲反射,就会很懵逼,不知道是干啥的,所以我们就引出一些问题来看看为什么需要反射 一.一个需求引出反射 看下面的问题 根据配置文件reflection.properties指定信息,创建People对象并调用方法hi classullpath= com.reflection.People method=hi 思考:使用现有技术,能做吗? 我们

  • Java基础之FastJson详解

    一.fastJson将json格式字符串转化成List集合 注:json格式字符串必须符合数组型格式如[{"a":a},{"b":b}] 场景一:前端向后台传递数组格式的json字符串,如何转化成List集合 List<AccountBean> readJson2List =JSON.parseArray(json, AccountBean.class)注意这里是Bean.class而不是List.class @Test public void read

随机推荐