JavaIO中的常用处理流

在前面,我们了解了有关JavaIO流基础的使用,其中对于IO流来说最基础的四大基类就是InputStreamOutputStreamReaderWriter。而我们对文件操作的最常用的子类就是FileInputStreamFileOutputStreamFileReaderFileWriter四大类,他们的用法基本上是完全一样的,只不过前两个是操作字节的,后两个是操作字符的。


字节流和字符流的区别

1、首先操作单元不同。字节流操作的单元是数据单元是8位的字节,字符流操作的是数据单元为16位的字节。

2、其次实际上字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作文件。

缓冲区

缓冲区可以简单地把缓冲区理解为一段特殊的内存。它的主要作用是:

  • 1、某些情况下,如果一个程序频繁地操作一个资源(如文件或数据库),则性能会很低,此时为了提升性能,就可以将一部分数据暂时读入到内存的一块区域之中,以后直接从此区域中读取数据即可,因为读取内存速度会比较快,这样可以提升程序的性能。
  • 2、在字符流的操作中,所有的字符都是在内存中形成的,在输出前会将所有的内容暂时保存在内存之中,所以使用了缓冲区暂存数据。如果想在不关闭时也可以将字符流的内容全部输出,则可以使用Writer类中的flush()方法完成。

字节流和字符流的使用

开发中究竟用字节流好还是用字符流好呢?

  • 在所有的硬盘上保存文件或进行传输的时候都是以字节的方法进行的,包括图片也是按字节完成,而字符是只有在内存中才会形成的,所以使用字节的操作是最多的。
  • 具体哪个好要是具体环境而定。比如我们要将字符类文件的内容读取出来对立面的内容进行操作那么这个时候选用字符流更为合适。如果不需要对内容进行操作只是单纯的文件传输例如文件拷贝那么选用字节流更合适。

FileReader和FileWriter类说明

public class FileReader extends InputStreamReader extends Reader extends java.lang.Object
  • FileReader不是Reader的子类,而是转换流的子类。
public class FileWriter extends OutputStreamWriter extends Writer extends java.lang.Object
  • FilWriter不是Writer的子类,而是转换流的子类。

也就是说,不管如何,虽然是以字符的输出流形式,操作字节流输出流,但是实际上还是以字节的形式输出。而字符的输入流虽然是以字符的形式操作,但是还是使用了字节流,也就是说,在传输或者从文件读取数据的时候,文件里真正保存的数据永远是字节。


带Buffered的处理流

  • BufferedInputStream / BufferedOutputStreamBufferedReader / BufferedWriter

这些处理流都是内置一个缓冲区(大小为8kb)。前者处理字节流,后者处理字符流。

常用方法

方法名 用法说明
boolean ready() 判断此流是否可以读取字符。
int read() 读取单个字符、以整数形式返回。如果读到in的结尾则返回-1。
int read(char[] cbuf, int off, int len) 将in中len个字符读取到cbuf从下标off开始长度len中。
String readLine() 读取一行。
boolean markSupported() 判断此流是否支持标记。
void mark(int readAheadLimit) 标记此流此时的位置。
void reset() 重置in被最后一次mark的位置。
long skip(long n) 丢弃in中n个字符。
void write(int c) 将一个单个字符写入到cb中。
void write(char cbuf[], int off, int len) 将一个从下标off开始长度为len个字符写入cb中。
void write(String s, int off, int len) 将一个字符串的一部分写入cb中。
void newLine() 写入一个换行符。
void flush() 刷新此流、同时刷新底层out流。
void flushBuffer() 将cb中缓存的字符flush到底层out中。
void close() 关闭此流、释放与此流有关的资源。
  • 从流里面读取文本,通过缓存的方式提高效率,读取的内容包括字符、数组和行。
  • 缓存的大小可以指定,也可以用默认的大小。大部分情况下,默认大小就够了。
  • 需要注意的是这里提供了markreset功能,也就是可以记住读取的位置,将来可以回滚,重新读取。这需要在读取数据时避免对缓冲区中的这部分数据覆盖掉,需要保存起来,同时保存的长度可以在mark的时候指定。调用reset可以回滚,但是必须mark过,而且mark过后读取的数据不能超过mark的时候设置的大小,否则会失效,调用reset会抛出异常。
public class Buffer_Test {public static void main(String[] args) {//        BufferedOutputStream 和 FileIOutputStream 用法完全一致//这两个处理流直接操作的是缓冲区BufferedOutputStream out;BufferedInputStream in = null;  //输入流  用法和fileInputStream完全一致try {in = new BufferedInputStream(new FileInputStream("D:\\Java文件IO\\Test\\a.txt"));//参数:字节流必须上输入流  第二个参数可以指定缓冲区大小  单位是字节for (int i = 0; i < 1024 * 9; i++) {in.read();  //只有第一次会从文件中读8K放入缓冲区,// 之后就直接从缓冲区中读取 不用进行文件IO//直到将缓冲区当中数据读完 再次读取8K数据刷新原有的缓冲区}out = new BufferedOutputStream(new FileOutputStream(  //节点流是直接操作数据的"D:\\Java文件IO\\Test\\a.txt", true));out.write(23);  //会将写的数据先存入缓冲区  让然后攒够8K 一次性写入文件//写入之后将缓冲区清空(实际上是将下标重新移动到初始位置,会将原数据覆盖)  继续接收新数据//写的时候要注意 调用flush 方法  和 close方法可以刷新缓冲区//或者是你写入的数据数量大于了缓冲区的大小可以不调用这两个方法out.flush();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}
}
  • read()方法的执行过程是:直接从源文件读取8192字节大小(或者字符大小)的数据,每当我们进行读取时,就直接从 buf 也就是缓存中去读写,如果读取的内容的大小已经大于了buf的长度,那么 buf 直接返回内存中指定需要的数据(内存大小8192,如果4096的内容已经都去了,这一次要读取8192,那么直接将剩余的4096字节的内容读取,再对磁盘进行交互),然后再读取源文件8192大小,返回给buf缓存,再返回给read(),直到满足需求。
  • write()方法,同样,先把数据写入缓存,当调用write()方法时,直接从缓存中去写入,如果写入的大小大于了 buf 的大小,那么直接flush(),再去将内存更新,再写入。
  • read 方法和 write 方法一样。本质上提升了效率,减少了磁盘的交互。

存在意义

为什么需要带Buffered处理流?

  • 为了提高字符读取的效率。

BufferedInputStreamBufferedOutputStream这两个类分别是FilterInputStreamFilterOutputStream的子类,作为装饰器子类。并且构造函数需要FilterInputStream/FilterOutputStream的子类入参。

BufferedReaderBufferedWriter这两个类分别是ReaderWriter的子类,作为装饰器子类。并且构造函数需要Reader/Writer的子类入参。

使用它们可以防止每次读取/发送数据时进行实际的写操作,代表着使用缓冲区。我们有必要知道不带缓冲的操作,每读一个字节就要写入一个字节,由于涉及磁盘的IO操作相比内存的操作要慢很多,所以不带缓冲的流效率很低。带缓冲的流,可以一次读很多字节,但不向磁盘中写入,只是先放到内存里。等凑够了缓冲区大小的时候一次性写入磁盘,这种方式可以减少磁盘操作次数,速度就会提高很多!

也就是说如果当前缓冲区没有数据,则调用底层reader去读取数据到缓冲区;如果有数据则直接读取。默认的 缓冲大小是8k,也就是每次读取都是8k为单位。

BufferedReader中还提供了一行一行读取的功能readLine函数,这不是Reader中的方法,这种方法可以把换行符(\r、\n、\r\n)去掉。

flush的作用

BufferedOutputStreamclose()时会自动flushBufferedOutputStream或者Bufferedwriter在不调用close()的情况下,缓冲区不满,又需要把缓冲区的内容写入到文件或通过网络发送到别的机器时,才需要调用flush

源码分析

BufferedInputStream为例:源码分析

要想读懂BufferedInputStream的源码,就要先理解它的思想。

  • BufferedInputStream的作用是为其它输入流提供缓冲功能。创建BufferedInputStream时,我们会通过它的构造函数指定某个输入流为参数。BufferedInputStream会将该输入流数据分批读取,每次读取一部分到缓冲中;操作完缓冲中的这部分数据之后,再从输入流中读取下一部分的数据。

为什么需要缓冲呢?

  • 原因很简单,效率问题!缓冲中的数据实际上是保存在内存中,而原始数据可能是保存在硬盘或NandFlash等存储介质中;而我们知道,从内存中读取数据的速度比从硬盘读取数据的速度至少快10倍以上。

那干嘛不干脆一次性将全部数据都读取到缓冲中呢?

  • 第一,读取全部的数据所需要的时间可能会很长。
  • 第二,内存价格很贵,容量不像硬盘那么大。

额外知识

1、类自带的缓冲区,与我们自己创建的缓冲区有什么不同?

2、既然FileWriter和Filereader中已经带有缓冲区,还要有BufferReader和BufferWriteer?

  • Java 在IO操作中,都会有一个缓冲区的,它们不同在于缓冲区的大小。BufferWriter更合理的使用缓冲区,在处理大量的数据时,FileWrite的效率明显不如BufferWriter

带Object的处理流

带Object的处理流被称为对象处理流,常见的有两种:ObjectInputStreamObjectOutputStream

对象流可以将一个对象写出,或者读取一个对象到程序中(对象持久化),也就是执行了序列化和反序列化的操作。

序列化的概念

将一个对象存放到某种类型的永久存储器上称为保持。如果一个对象可以被存放到磁盘或磁带上,或者可以发送到另外一台机器并存放到存储器或磁盘上,那么这个对象就被称为可保持的。

  • 在Java中,序列化、持久化、串行化是一个概念。
  • 参考链接:序列化与反序列化

基本使用方法

方法名 用法说明
Object readObject() 读取对象,需要进行类型转换。
void writeObject(Object obj) 将对象写入文件中。
... 根据对象属性的不同,还有很多读写对象的属性的方法。
class Dog implements Serializable {private static final long serialVersionUID = -5156631308412187014L;private String name;private int age;public Dog() {}public Dog(String name, int age) {this.name = name;this.age = age;}//省略get/set方法
}public class ObjectStreamTest {  //对象持久化的过程   数据落地public static void main(String[] args) {Dog dog = new Dog("nickel", 8);//把对象变成字节存储到文件中ObjectOutputStream out = null;ObjectInputStream in = null;try {out = new ObjectOutputStream(new FileOutputStream("D:\\Java\\IoTest\\dog.txt"));out.writeObject(dog);System.out.println("---------------反序列化的结果如下-------------------");in = new ObjectInputStream(new FileInputStream("D:\\Java\\IoTest\\dog.txt"));Dog dog1 = (Dog) in.readObject();System.out.println(dog1);} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}}
}
  • 注意:我们的对象类一定要实现 Serializable 接口(java.io.Serializable接口没有任何方法,它只作为一个“标记者”,用来表明实现了这个接口的类可以考虑串行化。类中没有实现Serializable的对象不能保存或恢复它们的状态) 不然程序就会报错。

带Data的处理类

DataInputStreamDataOutputStream类创建的对象称为数据输入流和数据输出流。它们运行程序按着机器无关的风格读取Java原始数据。也就是说,当读取一个数值时,不必再关心这个数值应当是多少个字节。

常用方法

基本使用方法

public class Data_StreamTest {public static void main(String[] args) {DataOutputStream out = null;DataInputStream in = null;People p = new People("张三", 13, new A(1, "dsad"));try {out = new DataOutputStream(new FileOutputStream("D:\\Java\\IoTest\\p.txt"));out.writeUTF(p.getName());out.writeInt(p.getAge());out.writeInt(p.getA().getSex());out.writeUTF(p.getA().getName());in = new DataInputStream(new FileInputStream("D:\\Java\\IoTest\\p.txt"));People p1 = new People();p1.setName(in.readUTF());p1.setAge(in.readInt());A a = new A();a.setSex(in.readInt());a.setName(in.readUTF());p1.setA(a);System.out.println(p1);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}
}class People {private String name;private int age;private A a;public People() {}public People(String name, int age, A a) {this.name = name;this.age = age;this.a = a;}//省略get/set方法
}class A{private int sex;private String name;public A() {}public A(int sex, String name) {this.sex = sex;this.name = name;}//省略get/set方法
}

对象流和数据流的区别与联系

1、Object相当于装IO流的一个盒子,我们可以把对象比作一个个拼好的积木,IO流就是拼积木的积木块,那么如果要搬走积木(对象),肯定需要把积木(对象)先拆了,再扔进盒子(Object)里,这就是为什么对象要序列化(Serializable)。

2、当然装的时候我们可以有两种装法一种是全放入(output.writeObject(this))第一种盒子(ObjectInputStream),另一种是分类别 (如:比如将屋顶、地板、这些流里面的) 放入(output.writeUTF(number),output.writeUTF(name),output.writeInt(age)…)第二种盒子(DataInputStream),所以在搬到另一个地方的时候,第一种盒子里我们把混在一起的积木块倒出((Member)intput.readObject()),第二种盒子则是分块拿出来({input.readUTF(),input.readUTF(),input.readInt()…})。

3、处理基本类型的时候没有什么很大的区别,区别是Object的可将一个实现了序列化的类实例写入输出流中,ObjectInput可以从输入流中将ObjectOutput输出的类实例读入到一个实例中。DataOutputStream只能处理基本类型。(Object处理的类必须是实现了序列化的类)。

【JavaIO流】JavaIO中的常用处理流相关推荐

  1. java中什么方法用来清空流_这个真的写的很细,JavaIO中的常用处理流,看完只有10%的人还不懂了...

    JavaIO中的常用处理流 在前面,我们了解了有关JavaIO流基础的使用,其中对于IO流来说最基础的四大基类就是InputStream.OutputStream.Reader.Writer.而我们对 ...

  2. day27-API-java流的三大分类,常用的流(文件流,对象流, 缓冲流, 转换流, PW)

    文章目录 一. java流的三大类 1. 输出流和输入流 2. 字节流和字符流 3. 节点流和处理流 二. 字节流 1. 文件流 FIS和FOS 1.1 文件输出流:FileOutputStream ...

  3. python 二进制流_Python中对字节流/二进制流的操作:struct模块简易使用教程

    前言 前段时间使用Python解析IDX文件格式的MNIST数据集,需要对二进制文件进行读取操作,其中我使用的是struct模块.查了网上挺多教程都写的挺好的,不过对新手不是很友好,所以我重新整理了一 ...

  4. java中什么是字节流和字符流_java中字节流与字符流的区别是什么

    字节(Byte)是进行io操作的基本数据单位,在程序进行字节数据输出时可以使用OutputStream类完成 此类定义如下: public abstract class OutputStream ex ...

  5. Java输入/输出流体系中常用的流分类

    java输入/输出流体系中常用的流分类 分类 字节输入流 字节输出流 字符输入流 字符输出流 抽象基类 InputStream OutputStream Reader Writer 访问文件 File ...

  6. java中的常用的文件流_Java 基础(四)| IO 流之使用文件流的正确姿势

    image.png 一.什么是 IO 流? 想象一个场景:我们在电脑上编辑文件,可以保存到硬盘上,也可以拷贝到 U 盘中.那这个看似简单的过程,背后其实是数据的传输. 数据的传输,也就是数据的流动.既 ...

  7. JAVA中常用IO流类:BufferedReader和BufferedWriter读取文件操作

    一.BufferedReader 字符串缓冲读取类 构造方法:bufferedWriter bf = new bufferedWriter(Writer out ); 主要方法:void write( ...

  8. Java基础:常用IO流

    1. 数据流 1.1 概述 数据流是操作基本数据类型的流,分为数据输入流,数据输出流. 1.2 数据输入流 1.DataInputStream:数据输出流允许应用程序以适当方式将基本 Java 数据类 ...

  9. C#中数据流(文件流、内存流、网络流等)相关知识点梳理

    基本概念 C#中数据流的应用体现在方方面面,现在针其常用的几种类进行一次梳理. 数据流包括文件流(FileStream).内存流(MemoryStream).网络流(NetworkStream)以及读 ...

最新文章

  1. Xtreme.Toolkit.Pro编译简单教程
  2. HDU 5119 Happy Matt Friends(递推)
  3. bzoj2959 长跑
  4. VTK:PolyData之KochanekSplineDemo
  5. supervisord的安装使用
  6. mysql和mysqldump出现command not found 问题解决
  7. ★★★【庖丁解牛:纵向切入Asp.net 3.5控件和组件开发技术系列—(1)读者序】★★★...
  8. java编码解码工具类
  9. 对标TJA1043 SIT1043 带唤醒及故障保护的低功耗CAN FD总线收发器
  10. 动态随机存储器的刷新
  11. 面试5173的奇葩经历——老板与员工的博弈论
  12. 利用FDTD软件仿真拓扑光子(二)-光子晶体结构分析
  13. java 一周的第一天_Java获取某年某周的第一天
  14. python基础:web =html+ python
  15. 代理沙特SASO贸促会认证
  16. 办公室白领长时间久坐很伤身
  17. R语言 无法打开文件: No such file or directory
  18. click延时解决方案
  19. 【论文笔记】—毫米波雷达穿雾式高分辨率成像—Supervised—HawkEye系统—2020-CVPR
  20. 永久删除文件怎么恢复?

热门文章

  1. Javascript万年历
  2. Science重磅 | 新技术Slide-seq能以高空间分辨率测量全基因组的表达情况
  3. 想接私活?那你得来看看程序员接私活经验总结吧
  4. 小L的算法课堂——博弈论
  5. aarch64 poky linux,aarch64-poky-linux-gcc:error::没有这样的文件或目录
  6. 河南省计算机专业三本排名2015,河南三本大学排名【最新排行榜】
  7. Echarts实现堆叠图
  8. 移动WebApp开发-phoneGap+android入门(http://blog.csdn.net/cwb1128/article/details/18004505)
  9. 大数据时代,企业如何进行有效的信息资源整合?
  10. 【源码】数学研究者的Cleve_s实验室