文章目录
- 有关文件路径的知识
- 数据输入输出流
- DataInputStream数据输入流
- 键盘录入的几种方式
- DataInputStream流的另外几个成员方法
- DataOutputStream数据输出流
- 数据流复制文本文件
- 内存操作流
- ByteArrayOutputStream流与ByteArrayInputStream流
- ByteArrayOutputStream流
- ByteArrayInputStream流
- 歌曲大连唱
- CharArrayWriter流与CharArrayReader流
- CharArrayWriter流
- CharArrayReader流
- StringWriter流与StringReader流
- StringWriter流
- StringReader流
- 打印流
- 字符打印流PrintWriter
- 字节打印流PrintStream
- 随机访问流
- 暂停复制文件
- 把一个文件分割为多份
- 序列化流与反序列化流
- ObjectOutputStream流
- ObjectInputstream流
- 与IO流有关的属性集合
- Properties类的概述
- 序列流SequenceInputStream
- ZIP压缩输入输出流
- 之前在学习字节流与字符流的时候,知道Java中文件的分隔符可以采用下坡杠()也可以采用上坡杠(/),而下坡杠在Java字符串中作为转义符使用,所以要在Windows格式的路径名中使用()作为路径分隔符;
- 在Windows系统中,可以使用单独的上坡杠,这是因为大多数Windows文件处理系统将上坡杠作为文件分隔符;但是,我们不推荐这样做——Windows的系统功能可能会改变,并且在其他操作系统上,文件的分隔符可能并不相同;
- 为了程序的可移植性,应该使用正确的文件分隔符,对应的文件分隔符存放在常量字符串中,具体使用如下:
- 因为所有在java.io中的类都是讲相对路径名解释为起始于用户的当前工作目录,所以应该清楚当前的目录,可以通过:
- Java使用一种很聪明的策略来划分这两种职责,一些流可以从文件一起其他地方接收字节,另一些流可以将字节组合成为更加有用的数据类型;Java程序员采用将一个已经存在的流传递给另一个流的构造器方法,将这两种流结合起来,结合后的流被称为;例如:为了能从文件中读取数值,首先创建一个FileInputStream流,然后将它传递给一个DataInputstream的构造器;
- 首先,来看一下 继承体系:
- DataInputStream流本质还是一个字节流,它的父类是:FilterInputStream 类,包含其他一些输入流,它将这些流用作其基本数据源,可以直接传输数据或提供一些额外的功能
- FilterInputStream 类本身只是简单地重写那些将所有请求传递给所包含输入流的 InputStream 的所有方法,FilterInputStream 的子类可进一步重写这些方法中的一些方法,并且还可以提供一些额外的方法和字段;
- 就像FileInputStream没有读取数值类型的方法一样,数据输入流DataInputStream也没有从文件读取数值的方法;
- 数据流的 存在意义:
经常需要向流写入计算结果,或者从流中读取结果;数据流支持读取所有Java基本类型的方法,写入或者读取一个数值、字符、布尔值或者字符串;
- 数据流DataInputStream的 构造方法:
使用指定的底层 InputStream 创建一个 DataInputStream;
- 数据流DataInputStream的 成员方法:
- 代码演示:
其他几个读取数字的方法没办法通过读取文本文件演示,这里引入另外一个知识点,键盘录入的几种方式,然后演示读取数字的方法;
- 键盘录入方式1:
new Scanner对象,传入参数System.in,输入文字,按下Enter键之后,录入结束;
- 其实System.in是一个标准的输入流,in是System类里面的一个静态字段,它的返回值是一个InputStream流对象,这个输入流对象读取的是键盘的输入;
- Scanner对象的其中一个构造就需要InputStream流的参数;
- 也就是说,之所以我们能用这样一行代码从键盘读取数据,是因为Scanner对象的构造参数在,我们看一下Scanner构造所需要的参数:
我们来看一下给定文件读取数据:
- 根据构造可以知道,只要给定一个InputStream字节输入流,都可以读取数据,之前学习了很多关于该流的子类,都可以作为参数传递进去,我们来看一下效果:
- 键盘录入方式2:
后面学习到的流会越来越多,只要是构造方法中的参数需要一个InputStream类型的,给定参数为System.in,就可以从键盘录入数据,中间的这个流作为媒介存在;
DataInputStream流的另外几个成员方法
- 代码演示:
- 继承体系:
- 构造方法:
- 成员方法:
- 代码演示:
- 特点:
不直接关联文件,它只是在内存中进行数据的读写,总共有3对;
- 内存操作流的引入,为何需要内存操作流?
- 首先我们谈谈虚拟文件的概念,内存虚拟文件,把一块内存虚拟成一个硬盘上的文件,原来该写到硬盘文件上的内容会被写到这个内存中,原来该从一个硬盘上读取的内容可以改为从内存中直接读取;
- 如果程序在运行过程中要产生一些临时文件,可以用虚拟文件的方式来实现。我们不用访问硬盘,而是直接访问内存,会提高应用程序的效率。
- 内存操作流:用于处理临时存储信息的,程序结束,数据就从内存中消失。
- 分类:
ByteArrayInputStream
ByteArrayOutputStream
CharArrayReader
CharArrayWriter
StringReader
StringWriter
- 内存操作流的使用场景
- 内存操作流的内存虚拟文件功能
JDK中提供了和这两个类可实现类似内存虚拟文件的功能,我们将抓取到的计算机屏幕图像的所有像素数据保存在一个数组中,然后根据这个数组创建一个ByteArrayInputStream流对象,同时创建一个用于保存压缩结果的ByteArrayOutputStream流对象,将这两个对象作为参数传递给压缩函数,最后从ByteArrayOutputStream流对象中返回包含有压缩结果的数组。我们要在程序分配一个存储数据的内存块, 通常都用定义一个字节数组来实现的。
ByteArrayOutputStream流
- 流的概述
该类继承自OutputStream抽象类,他默认分配的是32个字节元素空间,内存空间不足时动态扩展为原来的2倍;
- 构造方法
- 成员方法
- 代码演示:
ByteArrayInputStream流
- 流的概述
该类继承自InputStream抽象类,它的内部缓冲区通过定义一个字节数组实现;
- 构造方法:
- 成员方法:
- 代码演示:
歌曲大连唱
现在给出两首歌,我想把他们使用上面的流拼接为一首歌曲;
这个流本身不能与文件进行数据传输,但是它可以结合其他流;
思路:结合字节流读取两个音频文件,临时存入字节数组当中,字节数组流读取字节写入最终的文件中;
本质上只使用字节流也可以完成该需求,这里只是演示一下内存流的存在意义;
需要注意的是,虽然字节流本质上什么文件都可以操作,但是不能将这里的音频文件转换为视频文件,视频文件比较特殊;
- 本质上是一对字符流,和前面的内存流一样,不需要关闭,但是没有前者通用;
CharArrayWriter流
- 构造方法:
- 成员方法:
- write()的执行流程:
CharArrayReader流
- 构造方法
- 成员方法
- 代码演示:
- 操作起字符串很方便;
StringWriter流
- 构造方法
- 成员方法
toString():特殊的toString(),可以将写入其中的字符串直接展示出来;write():
底层是使用StringBuffer来拼接字符串的;
StringReader流
- 构造方法:
- 成员方法
- 代码演示:
- 只能往出写数据,没有对应的读取数据的流;
- 进行文本输出时,应该使用,该流可以以文本格式打印字符串和数值,只能往出写数据,与数据流类似,尽管提供了一些很有用的输出方法,但却没有定义目的地,一个打印流必须与一个目标writer相结合;
- 构造方法:
构造方法很多,可以随意组合使用;
- 成员方法:
和之前字符流一样,他有close()与flush();
除此之外,他有很多重载的write()、print()、println(),以及格式化写入文件中的format();
并且需要注意的是:此流的构造可以指定是否开启自动刷新,如果开启了自动刷新,则只有在调用 println、printf 或 format的其中一个方法时才可能完成此操作,而不是所有方法都可以。
- 代码演示:


- 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式;
- 它还提供其他两项功能,与其他输出流不同,PrintStream 永远不会抛出 IOException;而是,异常情况仅设置可通过 checkError 方法测试的内部标志;
- 另外,为了自动刷新,可以创建一个 PrintStream;这意味着可在写入 byte 数组之后自动调用 flush 方法,可调用其中一个 println 方法,或写入一个换行符或字节 (’ ’)。
- PrintStream 打印的所有字符都使用平台的默认字符编码转换为字节,在需要写入字符而不是写入字节的情况下,应该使用 PrintWriter 类;
- 代码演示:
该流可以使用自动获取一个流,关联显示器;
- 与其他流的配合复制文件
- 与Scanner配合复制文件
- 什么是 随机访问文件流 RandomAccessFile
- 该类的实例支持读取和写入随机访问文件;
- 随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组,存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机访问文件以读取/写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。写入隐含数组的当前末尾之后的输出操作导致该数组扩展。该文件指针可以通过 getFilePointer 方法读取,并通过 seek 方法设置;
- 底层源码:
通过上面的源码,我们可以看到因为 实现了数据输入输出流,那么 ,因此这一个类就可以完成输入输出的功能了,他没有继承什么流,直接继承自Object类;
- 构造方法:
这里面第二个参数:String mode 有以下几种形式:(为什么这里的值是固定的而不弄成枚举形式,不然很容易写错,这是因为随机访问流出现在枚举类型之前,属于Java 历史遗留问题)
- 代码演示:(使用该流,注意:怎么写的怎么读,顺序不要乱;)
- 进行随机读取之前,先来介绍两个方法:
- 返回此文件中的当前偏移量;
- 设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。偏移量的设置可能会超出文件末尾。偏移量的设置超出文件末尾不会改变文件的长度。只有在偏移量的设置超出文件末尾的情况下对文件进行写入才会更改其长度。
- 这里所说的偏移量,也就是字节数。一个文件是有N个字节数组成,那么我们可以通过设置读取或者写入的偏移量,来达到随机读取或写入的目的。
- 代码演示:(使用该流)
注意:怎么写的怎么读取,顺序不能乱;使用writeUTF()写入数据的时候,会多写入两个字节,
如果你读取的内容中有汉字存在,给定的指针偏移量就不能出错,否则会报错
;
- 此流存在的意义:
我们在复制文件的时候,经常会有这样的需求,下载途中暂停下载,下次接着上次下载的地方继续;
我们可以在复制文件的时候,使用代码模拟异常,并记录异常出现时文件的指针到配置文件中,下次复制文件的时候,做严谨性判断,判断文件是否存在并且临时文件的大小是否与上次文件指针的位置一样,如果为否,重新复制文件,否则继续复制;
- 序列化与反序列化的概念
- Java中使用与流进行 深克隆,对象的深克隆是采用IO流来实现 使用 ObjectOutputStream 将对象写入文件中,然后再用ObjectInputStream读取回来,也就是说,如果一个对象的内部维护了另外一个对象,这个流也会复制出来
- 构造方法
- 成员方法:
该流有很多普通的方法和之前的流类似,这里只介绍写入对象的方法:

- 构造方法
- 成员方法:
- 代码演示:
测试类:
Student类:
- 注意:当我们去序列化一个Java对象时,要求我们这个对象所对应的类,必须实现一个序列化接口Serializable;
- 看这样一种现象:
我在执行完writeData()之后,修改了一下Student类中字段的访问修饰符,再去读取该文件中的对象,发现抛出了异常:
- 为什么会出现错误呢?
这是因为,序列化的时候,给对象实现了一个接口,
该接口没有任何内容,它的存在意义和我们之前学习
方法一样,都只是为了打一个标记,相当于给猪打一个”放心猪肉”的标签,我们在序列化的时候,写入文件的时候打的这样一个标记,读取数据的时候会再次比对这个标记,如果前后的标记不一样,读取失败,报出前后标记不一致的错误;
- 如何解决这个问题?
我们可以在自定义的Student类中将标记值给定,写上这样一行代码:
这行代码可以在Serializable接口当中找到复制,也可以你自己任意给定一个值;
我们可以下载一个
自动提示一个值;
- 再次进行上面的操作,不会抛出异常;
- 假如我现在只想要序列化某个字段,排除某些字段不要序列化进去,给这些不想序列化的字段前面加上关键字,表示不要序列化,这时候你再打印这个对象,对应的该属性的值为默认值;
测试类:
Student类:
- 如果现在有这样的一个需求,我想序列化多个Java对象,写入的时候很方便,但是读取的时候很不方便,需要挨个读取,不能跳过前几个对象,怎么做?
考虑到序列化与反序列化其实就是深克隆,与浅克隆不一样,把这些对象存储进一个容器对象,将容器进行序列化,反序列化出容器就可以取出里面的对象了;
之所以能序列化ArrayList对象,该类肯定实现了序列化接口Serializable;

- Properties 类表示了一个持久的属性集,可保存在流中或从流中加载,属性列表中每个键及其对应值都是一个字符串;
- 一个属性列表可包含另一个属性列表作为它的”默认值”;如果未能在原有的属性列表中搜索到属性键,则搜索第二个属性列表;
- 代码演示:
- 上面的存取键值对,它的父类就可以完成,那么Properties 本身存在的意义是什么?因为 Properties 继承于 Hashtable,所以可对 Properties 对象应用 put 和 putAll 方法。但不建议使用这两个方法,因为它们允许调用者插入其键或值不是 String 的项。相反,应该使用 setProperty() 和 getProperty();
- 现在有这样的一个需求,如何将键值对存储到文件当中,并且读取出来,使用原来的知识,一定是先遍历集合,取出键值对,配合PrintWriter流写入文件当中,并开启自动刷新,读取一个键值对,写入一行;但是这个需求,Properties 本身就可以全部做完,使用可以从输入流中读取属性列表,使用可以将此 Properties 表中的属性列表(键和元素对)写入输出流;
comments - 属性列表的描述,给null值会默认在配置文件上方写一行当前日期时间的注释;

- 注意:如果你的配置文件写入中文会乱码的话,在Settings里面进行设置,
- 继承体系:
- SequenceInputStream 表示其他输入流的逻辑串联,它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止;该流像串糖葫芦一样给你吧文件流串起来;
- 构造方法:
- 合并两个文件
- 合并多个文件
- 本质上,我们还是可以使用上面的办法完成多个文件的合并,因为SequenceInputStream本质上也是一个InputStream,可以将第一个该流对象作为参数传递给第二个该流的对象,但是这样太麻烦;
- SequenceInputStream还有另外一个构造方法,他需要一个Enumeration迭代器对象作为参数,之前学习过的集合Vector有一个方法elements(),可以返回该迭代器类型的对象,我们把这个迭代器对象直接给该流的构造方法,他会帮我们遍历每一个流;
- ZIP文件(通常)以压缩格式存储一个或更多文件,Java 中可以处理GZIP和ZIP以及JAR格式,操作流程基本上是一致的,这里只讨论ZIP格式;
- 处理ZIP文件的类在中而不在中,尽管不是中的一部分,但是ZIP类还是和的子类;
- ZipEntry
- 在每一个压缩文件中都会存在多个子文件,这每一个子文件在Java中就使用ZipEntry表示;
- ZipEntry常用的方法:
- 在实例化ZipEntry 的时候,要设置名称,此名称实际上就是压缩文件中每一个元素的名称;
- ZipOutputStream
- 如果想要完成一个文件或文件夹的压缩,就要使用ZipOutputStream类完成;
- ZipOutputStream常用的方法:
- 此类的功能就是完成ZIP格式输出的
- 继承关系:
- 在压缩文件中,每一个压缩的内容都可以用一个ZipEntry 表示,所以在进行压缩之前必须通过putNextEntry 设置一个ZipEntry 即可;
- 压缩文件:
运行结果:

- 压缩文件夹:
- ZipFile
- 是一个专门表示压缩文件的类;在Java中,每一个压缩文件都可以使用ZipFile表示,还可以使用ZipFile根据压缩后的文件名称找到每一个压缩文件中的ZipEntry并将其进行解压缩操作;
- 常用的方法有:
- ZipFile 在实例化的时候必须接收File 类的实例,此File 类的实例是指向一个压缩 *.zip 文件;
- 解压缩文件夹
1、压缩文件中的每一个压缩实体都使用ZipEntry 保存,一个压缩文件中可能包含一个或多个的ZipEntry 对象。
2、在JAVA中可以进行zip、jar、gz、三种格式的压缩支持,操作流程基本上是一样的
3、ZipOutputStream 可以进行压缩输出,但是输出的位置不一定是文件。
4、ZipFile 表示每一个压缩文件,可以得到每一个压缩实体的输入流
5、ZipInputStream 可以得到每一个实体,但是却无法得到每一个实体的输入流。
- JDK中的ZipInputStream与ZipOutputStream 在压缩与解压缩操作中容易出现乱码,建议大家使用Apache的ZipInputStream与ZipOutputStream,因为它可以设置字符编码charset,这样就能够保证在写入/读取文件时,最大限度的避免乱码问题的发生!









版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/146987.html