Java基础-IO流

流的原理

在Java程序中,对于数据的输入/ 输出操作以“流” (stream) 方式进 行;

J2SDK提供了各种各样的“流”类, 用以获取不同种类的数据;程序 中通过标准的方法输入或输出数 据。

Java的流类型一般位于java.io包中

数据源

data source. 提供原始数据的原始媒介。常见的:数据库、文件、其他程序、内存、网络连接、IO设备。

数据源就像水箱,流就像水管中流着的水流,程序就是我们最终的用户。 流是一个抽象、动 态的概念,是一连串连续动态的数据集合。

流的分类

流的方向:

输入流:数据源到程序(InputStream、Reader读进来)

输出流:程序到目的地(OutPutStream、Writer写出去)

处理数据单元:

字节流:按照字节读取数据(InputStream、OutputStream)

字符流:按照字符读取数据(Reader、Writer)

功能不同:

节点流:可以直接从数据源或目的地读写数据。

处理流(包装流):不直接连接到数据源或目的地,是其他流进行封装。目的主要是简化操作和提高性能.

节点流和处理流的关系:

节点流处于io操作的第一线,所有操作必须通过他们进行;

处理流可以对其他流进行处理(提高效率或操作灵活性)

IO流类的体系

InputStream和OutputStream

Java语言中最基本的两个字节输入输出类。

其他所有字节输入输出流类都继承自这两个基类。

这两个类都是抽象类,不能创建它们的实例,只能使用它们的子类.

Reader和Writer

Java语言中最基本的两个字符输入输出类。

其他所有字符输入输出流类都继承自这两个基类。

这两个类都是抽象类,不能创建它们的实例,只能使用它们的子类

FileInputStream/FileOutputStream

使用FileInputStream读取文件内容

abstract int read( );

int read( byte b[ ] );

int read( byte b[ ], int off, int len );

int available( );

close( );

使用FileOutputStream写内容到文件

abstract void write( int b );

void write( byte b[ ] );

void write( byte b[ ], int off, int len );

void flush( );

void close( );

使用FileInputStream/FileOutputStream复制文件

FileReader和FileWriter

使用FileReader和FileWriter完成文件复制

缓冲字节流

BufferedInputStream和BufferedOutputStream

FileInputStream和FileOutputStream是节电流

BufferedInputStream和BufferedOutputStream是处理流(包装流)

读文件和写文件都使用了缓冲区,减少了读写次数,从而提高了效率

当创建这两个缓冲流的对象时时,会创建了内部缓冲数组,缺省使用32字节大小的缓冲区.

当读取数据时,数据按块读入缓冲区,其后的读操作则直接访问缓冲区

当写入数据时,首先写入缓冲区,当缓冲区满时,其中的数据写入所连接的输出流。使用方 法flush()可以强制将缓冲区的内容全部写入输出流

关闭流的顺序和打开流的顺序相反.只要关闭高层流即可,关闭高层流其实关闭的底层节点流Flush的使用:

手动将buffer中内容写入文件

缓冲字符流

BufferedReader

readLine() 读取一个文本行的数据

BufferedWriter

newLine(); 写入一个行分隔符。

使用缓冲字符流是复制文本文件常用的方式

转换流

InputStreamReader和OutputStreamWriter

用于将字节流转化成字符流,字符流与字节流之间的桥梁

InputStreamReader的作用是把InputStream转换成Reader

OutputStreamWriter的作用是把OutputStream转换成Writer

存在将字节流转换成字符流的转换流,因为字符流操作文本更简单

不存在把字符流转换成字节流的转换流,因为没有必要

System.in代表标准输入,即键盘输入,是InputStream的实例

打印流

PrintStream

PrintStream提供了一系列的print()和println(),可以实现将基本数据类型格式化成字符串输出。 对象类型将先调用

toString(),然后输出该方法返回的字符串

System.out就是PrintStream的一个实例,代表显示器

System.err 也是PrintStream的一个实例,代表显示器

PrintStream的输出功能非常强大,通常需要输出文本内容,都可以将输出流包装成 PrintStream后进行输出

PrintStream的方法都不抛出IOException

PrintWriter

PrintStream的对应字符流,功能相同,方法对应。

PrintWriter的方法也不抛出IOException

复制文件时可以使用PrintWriter代替BufferedWriter完成,更简单

缓冲字节流

DataInputStream和DataOutputStream

提供了可以存取所有Java基础类型数据(如:int,double 等)和String的方法。

处理流,只针对字节流,二进制文件

对象序列化

对象序列化 (Serialization)

将Java对象转换成字节序列(IO字节流)

对象反序列化 (DeSerialization)

从字节序列中恢复Java对象

为什么序列化

序列化以后的对象可以保存到磁盘上,也可以在网络上传输,使得不同的计算机可以共享对 象.(序列化的字节序列是平台无关的)

对象序列化的条件

只有实现了Serializable接口的类的对象才可以被序列化。Serializable接口中没有任何的方法,实现 该接口的类不需要实现额外的方法。

如果对象的属性是对象,属性对应类也必须实现Serializable接口

序列化能保存的元素

只能保存对象的非静态成员变量

不能保存任何成员方法和静态的成员变量

不保存transient成员变量

如果一个对象的成员变量是一个对象,这个对象的成员变量也会保存

串行化保存的只是变量的值,对于变量的任何修饰符,都不能保存

使用对象流把一个对象写到文件时不仅保证该对象是序列化的,而且该对象的成员 对象也必须是可序列化的。

如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操 作将会失败,并且会抛出一NotSerializableException。我们可以将这个引用标记为 transient,那么对象仍然可以序列化。

同一个对象多次序列化的处理

所有保存到磁盘中的对象都有一个序列化编号

序列化一个对象中,首先检查该对象是否已经序列化过

如果没有,进行序列化

如果已经序列化,将不再重新序列化,而是输出编号即可

如果不希望某些属性(敏感)序列化,或不希望出现递归序列

为属性添加transient关键字(完成排除在序列化之外)

自定义序列化(不仅可以决定哪些属性不参与序列化,还可以定义属性具体如何序列化)

序列化版本不兼容

修改了实例属性后,会影响版本号,从而导致反序列化不成功

解决方案:为Java对象指定序列化版本号serialVersionUID

字节/字符数组/字符串流

ByteArrayInutStream和ByteArrayOutputStream

数据源或目的地为:字节数组

只有字节流,没有字符流

节点流

CharArrayReader和CharArrayWriter

数据源或目的地为:字符数组

只有字符流,没有字节流

节点流

StringReader和StringWriter

数据源或目的地为:字符串

只有字符流,没有字节流

节点流

IO总结

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20200706A07WSL00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券