InputStream和OutputStream是所有的输入流和输出流的超类。他们两个都是抽象类。

read方法和write方法都是阻塞方法,这意味着如果不能里可以写入或者读取,比如因为网络问题,那么当前线程将会被阻塞。

InputStream的API:

方法摘要

int

available()
返回此输入流方法的下一个调用方可以不受阻塞地从此输入流读取(或跳过)的字节数。

void

close()
关闭此输入流并释放与该流关联的所有系统资源。

void

mark(int readlimit)
在此输入流中标记当前的位置。

boolean

markSupported()
测试此输入流是否支持 mark 和 reset 方法。

abstract int

read()
从输入流读取下一个数据字节。

int

read(byte[] b)
从输入流中读取一定数量的字节并将其存储在缓冲区数组 b 中。

int

read(byte[] b, int off, int len)
将输入流中最多 len 个数据字节读入字节数组。

void

reset()
将此流重新定位到对此输入流最后调用 mark 方法时的位置。

long

skip(long n)
跳过和放弃此输入流中的 n 个数据字节。

OutStream的API:

方法摘要

void

close()
关闭此输出流并释放与此流有关的所有系统资源。

void

flush()
刷新此输出流并强制写出所有缓冲的输出字节。

void

write(byte[] b)
将 b.length 个字节从指定的字节数组写入此输出流。

void

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

abstract void

write(int b)
将指定的字节写入此输出流。

Reader和Writer

用于读取和写入Unicode字符流的抽象类。和字节流的API类似。

看下面的API,何止是类似,兼职就是一样。因为不论是读取字节还是读取Unicode字符(这里其实是Unicode编码单元,2个字节),都是使用的int类型(4个字节)作为参数。

方法摘要

abstract void

close()
关闭该流。

void

mark(int readAheadLimit)
标记流中的当前位置。

boolean

markSupported()
判断此流是否支持 mark() 操作。

int

read()
读取单个字符。

int

read(char[] cbuf)
将字符读入数组。

abstract int

read(char[] cbuf, int off, int len)
将字符读入数组的某一部分。

int

read(CharBuffer target)
试图将字符读入指定的字符缓冲区。

boolean

ready()
判断是否准备读取此流。

void

reset()
重置该流。

long

skip(long n)
跳过字符。

组合流过滤器

如下使用:

DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream("person.dat")));

DataInputStream/ DataOutStream

数据输入流允许应用程序以与机器无关方式从基础输入流中读取基本 Java 数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。

通过它的方法可以看出它的常用使用场景:

PrintWriter和DataOutStream的API基本一致,一个是使用流的方式输出,一种是使用文本的方式输出,个人理解如果,输出后,需要打开文件看到显示效果不想看到乱码,那么要用PrintWriter,如果输出并不是为了查看,那么使用DataOutStream的话,性能应该会更高。

ByteArrayInputStream/ ByteArrayOutputStream

写入一个字节数组。

BufferedInputStream/ BufferedOutStream

通过在内部维护一个缓冲区,每次执行read方法的时候,它底层其实是读取了固定大小数目的字节到内存的缓冲区中(通过构造参数可以配置每次读取字节的数目,也就是缓冲区的大小)中,然后下次读取的时候,直接从内存的缓冲区中拿,不同在通过原始的方式(如网络或者磁盘)。

write的时候,也是只写入到内部的缓冲区中,当缓冲区满了才会做真正的写入操作。

一般将一个大的文件读取到内存,一般这么写:

  1. InputStream in=new FileInputStream(FILENAME);
  2. byte[] b=new byte[8192];
  3. int l=0;
  4. while(in.read(b,0,8192)!=-1){
  5.  
  6. }

这种是自己实现了一次性读取多个的方式。一般配置为8k,也就是8192。

也可以使用BufferedInputStream,如下:

  1. BufferedInputStream in=new BufferedInputStream(new FileInputStream(FILENAME));
  2. byte[] b=new byte[8192];
  3. int l=0;
  4. while(in.read(b,0,8192)!=-1){
  5. }

注意,这里的BufferedInputStream是在FileInputStream的外层,在调用BufferedInputStream.read()的时候,其实BufferedInputStream调用了FileInputStream的read(byte[] b, int off, int len)。

个人认为,如果是从文件中读取,那么还是使用第一种方式比较好,虽然第二种方式也能使用缓存,但是毕竟执行8000多遍read。

FilterOutputStream/ FilterInputStream

此类是过滤输出流的所有类的超类。它的功能很简单,就是构造器接受一个Stream,然后将上层的调用传递给它。

RandomAccessFile

此类的实例支持对随机存取文件的读取和写入。随机存取文件的行为类似存储在文件系统中的一个大型字节数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机存取文件以读取/写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。写入隐含数组的当前末尾之后的输出操作导致该数组扩展。该文件指针可以通过 getFilePointer 方法读取,并通过 seek 方法设置。

有如下方法是现实随机读写:

void

seek(long pos)
设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。

 

InputStreamReader/OutputStreamWriter

InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,否则可能接受平台默认的字符集。

每次调用 InputStreamReader 中的一个 read() 方法都会导致从基础输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从基础流读取更多的字节,使其超过满足当前读取操作所需的字节。

为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。例如:

BufferedReader in

= new BufferedReader(new InputStreamReader(System.in));

 

OutputStreamWriter类似于上面:

OutputStreamWriter 是字符流通向字节流的桥梁:使用指定的 charset 将要向其写入的字符编码为字节。它使用的字符集可以由名称指定或显式给定,否则可能接受平台默认的字符集。

每次调用 write() 方法都会针对给定的字符(或字符集)调用编码转换器。在写入基础输出流之前,得到的这些字节会在缓冲区累积。可以指定此缓冲区的大小,不过,默认的缓冲区对多数用途来说已足够大。注意,传递到此 write() 方法的字符是未缓冲的。

为了达到最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中以避免频繁调用转换器。例如:

Writer out

= new BufferedWriter(new OutputStreamWriter(System.out));

 

注意:根据上面的描述,OutputStreamWriter是自带缓冲区的。但是InputStreamReader没有。

BufferedReader/BufferedWriter

BufferedReader:

从字符输入流中读取文本,缓冲各个字符,从而提供字符、数组和行的高效读取。

可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。

通常,Reader 所作的每个读取请求都会导致对基础字符或字节流进行相应的读取请求。因此,建议用 BufferedReader 包装所有其 read() 操作可能开销很高的 Reader(如 FileReader 和 InputStreamReader)。例如,

BufferedReader in

= new BufferedReader(new FileReader("foo.in"));

 

将缓冲指定文件的输入。如果没有缓冲,则每次调用 read() 或 readLine() 都会导致从文件中读取字节,并将其转换为字符后返回,而这是极其低效的。

BufferedReader有一个readLine()方法。可以读取一行。这个在InputStreamReader和FileReader中是没有的。

FileReader/ FileWriter

用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要自己指定这些值,可以先在 FileInputStream 上构造一个 InputStreamReader。

也就是说,FileReader内部的实现就是:

new InputStreamReader(new File…),但是InputStreamReader是可以指定字符集编码的,但是使用的是默认值。

 

序列化

类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。

java.io.ObjectOutputStream:表示对象输出流

它的writeObject(Object obj)方法可以对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。

java.io.ObjectInputStream:表示对象输入流

它的readObject()方法源输入流中读取字节序列,再把它们反序列化成为一个对象,并将其返回。

只有实现了Serializable或Externalizable接口的类的对象才能被序列化,否则抛出异常。

对象的序列化会将对象中的所有属性,包含私有属性都序列化。

对象的序列化会将对象中的引用指向的对象序列化,而不是引用本身。

可以讲一个对象序列化到一个字节数组然后再反序列化回来实现对对象的深拷贝。

在反序列化的时候,如果类的定义发生了变化,那么ObjectInputStream将"尽力"将流对象转换为当前的类版本。不能转换的字段将会被设置为默认值。

 

 

 

 

JAVA 流与文件的更多相关文章

  1. java流和文件 保存字节级数据(写)

    重要的知识点: 流的概念:  从数据源到I/O类的输入流(in)    从I/O类到数据接收器的输出流(out) I/O包含子类较多的有四大家族:InputStream,OutputStream,Re ...

  2. (转载)java基础:关于java流与文件操作

    原文摘自: http://www.blogjava.net/haizhige/archive/2008/08/03/219668.html 1.描述:流是字节数据或字符数据序列. Java采用输入流对 ...

  3. java基础:关于java流与文件操作

    1.描述:流是字节数据或字符数据序列.Java采用输入流对象和输出流对象来支持程序对数据的输入和输出.输入流对象提供了数据从源点流向程序的管道,程序可以从输入流对象读取数据:输出流对象提供了数据从程序 ...

  4. Java流和文件

    File类:java.io包下与平台无关的文件和目录 java可以使用文件路径字符串来创建File实例,文件路径可以是绝对路径,也可以是相对路径,默认情况下,相对路径是依据用户工作路径,通常就是运行J ...

  5. java流、文件以及IO

    读写文件 一个流被定义为一个数据序列.输入流用于从源读取数据,输出流用于向目标写数据. 输入流和输出流的类层次图. FileInputStream FileInputStream用于从文件中读取数据, ...

  6. Java——流、文件与正则表达式

    0. 字节流与二进制文件 我的代码 package javalearn; import java.io.DataInputStream; import java.io.DataOutputStream ...

  7. Java流,文件和I/O

    java.io包中包含几乎所有可能永远需要在Java中执行输入和输出(I/ O)类.所有这些数据流代表一个输入源和输出目标. java.io包中的流支持多种数据,如基本类型,对象,本地化的字符等 流可 ...

  8. java流与文件的操作 文件加密

    课后作业 1,源代码 import java.io.*; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttribu ...

  9. JAVA流读取文件并保存数据

    如图有文本如下数据 写方法读取数据 private String[][] getData(){ // 使用ArrayList来存储每行读取到的字符串 ArrayList<String> a ...

随机推荐

  1. PHP学习(4)——数组的使用

    1.数组的概念 数组就是一个用来存储一系列变量值的命名区域. 每个数组元素有一个相关的索引(也成为关键字),它可以用来访问元素. PHP允许间隔性地使用数字或字符串作为数组的索引. 2.数字索引数组 ...

  2. mapreducer计算原理

    mapreducer计算原理

  3. 使用TensorFlow训练SSD(二):数据的准备

    在进行模型的训练之前,需要准备好相关的数据,相关的数据还需要进行标注.这篇博客将使用labelImg标注工具来进行数据的处理. 首先可从https://github.com/tzutalin/labe ...

  4. vim 显示行号 查找的命令简单总结

    1. linux vim 进行查找的方法 在command 模式下面 输入 /what-you-search 就可以搜索 注意  n 是向下查找 N 是向上查找 不想搜索了 输入 :set nol 就 ...

  5. Docker CE 下载方式

    1. 找到一个网址挺好的 https://download.docker.com/linux/ubuntu/dists/xenial/pool/stable/arm64/ mark 一下 以后用.

  6. tee、vi/vim命令

    一.tee:多重定向 语法:       tee [OPTION] ... [FILE] ... 参数:       将标准输入复制到每个FILE,也复制到标准输出. -a,--append      ...

  7. linux命令 ip

  8. MyBatis学习存档(1)——入门

    一.简介 MyBatis的前身是iBatis,本是Apache的一个开源的项目 MyBatis是一个数据持久层(ORM)框架,把实体类和SQL语句之间建立了映射关系,是一种半自动化的ORM实现 MyB ...

  9. 树莓派安装SSH

    1. 安装ssh sudo apt-get install openssh-server 2. 检查树莓派SSH服务是否开启 ps -e|grep ssh 3. SSH服务开启 sudo /etc/i ...

  10. 【原创】大数据基础之Chronos

    官方:https://mesos.github.io/chronos/ mesos集群中替换crontab Chronos A fault tolerant job scheduler for Mes ...