点击上方“罗晓胜”,马上关注,您的支持对我帮助很大
上期文章
/ 前言 /
文件是什么?
文件是所有数据存储的基本单位,你操作的一切,例如:歌曲,影视,游戏等,都是基于文件计算传输。
流是什么?
大家都知道流重要,事实确实重要,网络传输就是用流,文件的操作也要用流。
文件(File)和流(Stream)是既有区别又有联系的两个概念。
-
文件(File):
-
是计算机管理数据的基本单位,同时也是应用程序保存和读取数据的一个重要场所。
-
存储介质:文件是指在各种存储介质上(如硬盘、可移动磁盘、CD等)永久存储的数据的有序集合,它是进行数据读写操作的基本对象。
-
特性:每个文件都有文件名、文件所在路径、创建时间及访问权限等属性
-
-
流(Stream)
-
是字节序列的抽象概念,例如文件、输入/输出设备、内部进程通信管道等。流提供一种向后备存储器写入字节和从后备存储器读取字节的方式
-
存储介质:除了和磁盘文件直接相关的文件流以外,流还有多种类型。流可以分布在网络中、内存中或者是磁带中。
-
特性:程序从输入流读取数据,向输出流写入数据。Java是面向对象的程序语言,每一个数据流都是一个对象,它们提供了各种支持“读入”与“写入”操作的流类。
-
/ 正文 /
文件与流IO
要点
-
文件管理
-
File类的使用与文件操作
-
-
流的概念及API
-
流的概念
-
-
节点流与处理流的使用
-
节点流
-
处理流
-
-
对象的序列化
-
序列化
-
transient关键字
-
文件管理
-
文件管理的概述
-
文件的属性信息
-
文件的检查
-
文件的删除等
-
不包括文件的访问
-
Java中的对文件的管理,通过java.io包中的File类实现
-
Java中文件的管理,主要是针对文件或是目录路径名的管理
-
File类
-
File类
-
File类的构造方法
-
File 变量名 = new File(String pathname) ;
File 变量名 = new File(String parent,Stirng child) ;
File 变量名 = new File(File parent,Stirng child) ;
//通过将给定路径名字符串转换成抽象路径名来创建一个新File 实例
File f1 = new File (“d:/temp/abc.txt”);
//根据 parent 路径名字符串和 child 路径名字符串创建一个新File 实例
File f3 = new File(“d:/temp”,“abc.txt”);
//根据 parent 抽象路径名和 child 路径名字符串创建一个新 File实例
File f = new File(“d:/temp”);
File f4 = new File(f,“abc.txt”);
File类常用方法
方法 | 含义 |
---|---|
boolean createNewFile() | 当且仅当不存在具有此抽象路径名指定的名称的文件时,原子地创建由此抽象路径名指定的一个新的空文件。 |
static File createTempFile(String prefix,String suffix) | 在默认临时文件目录中创建一个空文件,使用给定前缀和后缀生成其名称 |
static File createTempFile(String prefix,Stirng suffix,File directory) | 在指定目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称 |
boolean exists( ) | 测试此抽象路径名表示的文件或目录是否存在 |
boolean delete( ) | 删除此抽象路径名表示的文件或目录 |
boolean equals(Object obj) | 测试此抽象路径名与给定对象是否相等 |
boolean canRead() | 测试应用程序是否可以读取此抽象路径名表示的文件 |
boolean canWrite() | 测试应用程序是否可以修改此抽象路径名表示的文件 |
String[] list( ) | 返回由此抽象路径名所表示的目录中的文件和目录的名称所组成字符串数组 |
String getAbsolutePath( ) | 返回抽象路径名的绝对路径名字符串 |
String getName( ) | 返回由此抽象路径名表示的文件或目录的名称,不包括路径名称 |
String getPath( ) | 将此抽象路径名转换为一个路径名字符串 |
File[] listFiles() | 返回一个抽象路径名数组,这些路径名表示此抽象路径名所表示目录中的文件 |
boolean renameTo(File dest ) | 重新命名此抽象路径名表示的文件 |
long length( ) | 返回由此抽象路径名表示的文件的大小,以byte为单位 |
boolean mkdir( ) | 创建此抽象路径名指定的目录 |
boolean mkdirs( ) | 创建此抽象路径名指定的目录,包括创建必需但不存在的父目录。注意,如果此操作失败,可能已成功创建了一些必需的父目录 |
流的概念
-
流的概念
-
输入流 — 流入程序的数据
-
输出流 — 流出程序的数据
-
在java程序中,从输入流读取数据(读到内存中),而从输出 流输出数据(从内存存储到文件或显示到屏幕上)
-
流(Stream )的概念代表的是程序中数据的流通
-
数据流是一串连续不断的数据的集合
-
在Java程序中,对于数据的输入/输出操作是以流(Stream)的方式进 行的
-
流的分类
-
-
按流的方向不同
-
输入流、输出流
-
-
按处理数据的单位不同
-
字节流、字符流
-
-
按功能不同
-
节点流、处理流
-
-
Java语言中,控制数据流的类都放在java.io包中
字节流 | 字符流 | |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
-
java.io包中有两大继承体系
-
以byte处理为主的Stream类, 他们的命名方式是XXXStream
-
以字符处理为主的Reader / Writer类,他们的命名方式XXXReader或XXXWriter
-
InputStream、OutputStream、Reader、Writer这四个类,是这两大继承体系 的父类
-
字节输入流的主要方法
-
字节流—InputStream
-
此抽象类是表示输入字节流的所有类的超类
-
InputStream常用的方法
-
方法 | 含义 |
---|---|
int read( ) | 一次读取一个byte的数据,并以int类型把数据返回来,如果没有数据可以读了,会返回”-1” |
int read(byte[] buffer) | 把所读取到的数据放在这个byte数组中,返回一个int型的数据,这个int型数据存储了返回的真正读取到的数据byte数 |
int read(byte[] buffer,int offset,int length) | 读取length个字节,并存储到一个字节数组buffer 中,并从offset位置开始返回实际读取的字节数 |
void close( ) | 关闭此输入流并释放与该流关联的所有系统资源 |
-
字节流—OutputStream
-
此抽象类是表示输出字节流的所有类的超类
-
OutputStream常用的方法
-
方法 | 含义 |
---|---|
void write(byte[] buffer) | 将要输出的数组先放在一个byte数组中,然后用这个方法一次把一组数据输出出去 |
void write(byte[] buffer,int off,int len) | 将指定字节数组中从偏移量off 开始的len 个字节写入此输出流 |
abstract void write(int b) | 将指定的字节写入此输出流 |
void close( ) | 关闭此输出流并释放与此流有关的所有系统资源 |
void flush( ) | 刷新此输出流并强制写出所有缓冲的输出字节 |
-
字符流— Reader
-
用于输入字符流的抽象类
-
Reader常用的方法
-
方法 | 含义 |
---|---|
int read( ) | 一次读取一个char的数据,并以int类型把数据返回来,如果没有数据可以读了,会返回”-1” |
int read(char[] cbuffer) | 把所读取到的数据放在这个char数组中,返回一个int型的数据,这个int型数据存储了返回的真正读取到的数据char数 |
int read(char[] cbuffer,int offset,int length) | 读取length个字符,并存储到一个字节数组cbuffer中,并从offset位置开始返回实际读取的字符数 |
void close( ) | 关闭此Reader并释放与其关联的所有系统资源 |
-
字符流—Writer
-
输出字符流的抽象类
-
Writer常用的方法
-
方法 | 含义 |
---|---|
void write(char[] cbuffer) | 将要输出的数组先放在一个char数组中,然后用这个方法一次把一组数据输出出去 |
void write(char[] cbuffer,int off,int len) | 将指定字符数组中从偏移量off 开始的len 个字符写入此输出流 |
int write(int b) | 将指定的字符写入此输出流 |
void write(String str) | 写入字符串 |
void write(String str, int off,int len) | 将指定字符串中从偏移量off 开始的len 个字符写入此输出流 |
void close( ) | 关闭此输出流并释放与此流有关的所有系统资源 |
void flush( ) | 刷新此输出流并强制写出所有缓冲的输出字节 |
节点流
-
节点流
-
节点流:从一个特定的数据源(节点)读写数据(如:文件、内存) 的类叫做节点流类
-
这些节点类跟数据源或数据目的地做直接连接用的
-
在java.io包中,字节继承体系有三种节点类,而字符继承体系有四 种节点类
-
类型 | 字节流 | 字符流 |
---|---|---|
File | FileInputStream、FileOutputStream | FileReader、FileWriter |
Memory Array | ByteArrayInputStream ByteArrayOutputStream | CharArrayReader CharArrayWriter |
Memory String | StringReader、StringWriter | |
Piped | PipedInputStream PipedOutputStream | PipedReader PipedWriter |
节点流方法InputStream
方法 | 含义 |
---|---|
int read( ) | 这个方法没有参数,一次读取一个byte的数据,并以int类型把数据返回来,如果没有数据可以读了,会返回”-1”。 |
int read(byte[] b) | 这个方法有一个byte数据类型的参数,这个方法会把所读取到的数据放在这个byte数组中,返回一个int型的数据,这个int型数据存储了返回的真正读取到的数据byte数。 |
int read(byte[] b,int off,int len) | 将输入流中最多len 个数据字节读入字节,返回值同上。 |
void close( ) | 关闭此输入流并释放与该流关联的所有系统资源。 |
int available( ) | 获取这个流中还有多少个byte 的数据可以读取。返回值告诉我们还有多少个byte的数据可以读取。注:这个方法会产生IOException异常,另外如果InputStream对象调用这个方法的话,它只会返回0,这个方法必须由继承InputStream类的子类对象调用才有作用。 |
long skip(long n) | 跳过和放弃此输入流中的n 个数据字节。返回值返回真正跳过的字节数。 |
节点流方法OutputStream
方法 | 含义 |
---|---|
void write(byte[] b) | 将要输出的数组先放在一个byte 数组中,然后用这个方法一次把一组数据输出出去。 |
void write(byte[] b, int off, int len) | 将指定字节数组中从偏移量off开始的 len 个字节写入此输出流 |
void write(int b) | 将要输出的byte数据传给这个方法就可。 |
void close() | 关闭此输出流并释放与此流有关的所有系统资源 |
void flush() | 刷新此输出流并强制写出所有缓冲的输出字节。 |
-
节点流的方法— OutputStream
-
使用write方法输出数据时,有些数据并不会马上输出到我们指 定的目的,通常会在内存中有个暂存区,有些输出的数据会暂 时存放在这里,如果我们想要立刻把数据输出到目的地,不要 放在暂存区中时,可以调用”flush”这个方法来对暂存区做清除的动作。
-
同样,数据输出完后,记得把它”close”,在调用close这个方法时,会先调用flush这个方法,以确保所有的数据都已经输出 到目的地了。
-
注意:
-
-
节点流的方法— Reader
-
注:
-
Reader是输入字符数据用的类,它所提供的方法和InputStream 类一样,差别在于InputStream类中用的是byte类型,而Reader 类中用的是char类型。
-
-
Reader类中没有available方法,取而代之的是”ready” 方法,这个方法会去检查Reader对象是否已经准备好输 入数据了,如果是返回true,反之返回false。
-
节点流的方法 — Writer
-
注:
-
Writer类是输出字符数据的类,同样地,提供的方法和OutputStream类中的方法类似,将OutputStream类中用到的byte类型,换成char类型就可。
-
-
Writer类另外提供了两个writer方法,所以Writer类有5 个writer方法,多出来的两个只是把char数据换成String 对象而已,方便输出字符的数据。
文件的访问
-
文件的访问
-
FileInputStream
-
FileOutputStream
-
FileReader
-
FileWriter
-
了解了流操作的方法和File类的使用后,我们来看看如何访问一个 文件中的数据
-
在java.io包中,可以利用以下四种节点类来进行文件的访问
-
-
文件的访问— FileInputStream 示例 FileInputStreamDemo.java
-
构造方法
-
方法 | 含义 |
---|---|
FileInputStream(String fileurl) | 通过打开一个到实际文件的链接来创建一个FileInputStream,该文件通过文件系统中的路径名指定 |
FileInputStream(File fileobj) | 通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的File 对象file 指定 |
File f = new File(“d:/io/a.txt”);
FileInputStream fin1 = new FileInputStream(f);
FileInputStream fin2 = new FileInputStream(“d:/io/b.txt”);
-
文件的访问— FileReader 示例 FileReaderDemo.java
-
构造方法
-
方法 | 含义 |
---|---|
FileReader(String fileurl) | 通过打开一个到实际文件的连接来创建一个FileReader,该文件通过文件系统中的路径名指定 |
FileReader(File fileobj) | 通过打开一个到实际文件的连接来创建一个FileReader,该文件通过文件系统中的File 对象 file 指定 |
File f = new File(“d:/io/a.txt”);
FileReader fin1 = new FileReader(file);
FileReader fin2 = new FileReader(“d:/io/b.txt”);
-
文件的访问— FileOutputStream 示例 FileOutputStreamDemo.java
-
构造方法
-
方法 | 含义 |
---|---|
FileOutputStream(String fileurl) 创建一个向路径为fileurl的文件中写入数据的输出文件流 | |
FileOutputStream(String fileurl, boolean append) 创建一个向路径为fileurl的文件中写入数据的输出文件流,并将字节写在文件尾处 | |
FileOutputStream(File fileobj) 创建一个向指定 File对象fileobj表示的文件中写入数据的文件输出流 | |
FileOutputStream(File fileobj,boolean append) 创建一个向指定 File对象fileobj表示的文件中写入数据的文件输出流,并将字节写在文件尾处 |
-
文件的访问 — FileWriter
-
构造方法
-
方法 | 含义 |
---|---|
FileWriter(String fileurl) | 创建一个向路径为fileurl的文件中写入数据的输出文件流 |
FileWriter(String fileurl,boolean append) | 创建一个向路径为fileurl的文件中写入数据的输出文件流,并将字节写在文件尾处 |
FileWriter(File fileobj) | 创建一个向指定 File对象fileobj表示的文件中写入数据的文件输出流 |
FileWriter(File fileobj,boolean append) | 创建一个向指定 File对象fileobj表示的文件中写入数据的文件输出流,并将字节写在文件尾处 |
处理流
-
处理流
-
只用字节或是字符为单位来对数据做输入输出是不够的,有时候 我们需要一行一行的读数据,有时我们需要读取特定格式的数据, 因此Java提供了这样的机制,能把数据流作连接(chain),让原本没有特殊访问方法的流,通过连接到特殊的流后,变成可以用特定的方法来访问数据
-
“连接”在已存在的流(节点流或处理流)之上,通过对数据的 处理为程序提供更为强大的读写功能
-
处理流类的构造函数中,都必须接收另外一个流对象作为参数
-
常见的处理流类
种类\继承体系 | 字节 | 字符 |
---|---|---|
缓冲(Buffered) | BufferedInputStream, BuueredOutputStream | BufferedReader, BufferedWriter |
字符和字节转换 | InputStreamReader, OutputStreamWriter | |
对象序列化 | ObjectInputStream, ObjectOutputStream | |
特定数据类型访问 | DataInputStream, DataOutputStream | |
计数 | LineNumberInputStream | |
重复 | PushbackInputStream | |
打印 | PrintStream | PrintWriter |
-
常见处理流类 — 缓冲流(Buffered)
-
缓冲流对读写的数据提供了缓冲的功能,提高了读写的效率,同 时增加了一些新的方法
-
Java提供了以下缓冲流,其构造方法
-
方法 | 含义 |
---|---|
BufferedInputStream(InputStream in) | 创建了一个带有32字节缓冲区的缓冲输入流 |
BufferedInputStream(InputStream in, int size) | 创建了一个带有size大小缓冲区的缓冲输入流 |
BufferedOutputStream(OutputStream out) | 创建了一个带有32字节缓冲区的缓冲输出流 |
BufferedOutputStream(OutputStream out,int size) | 创建了一个带有size大小缓冲区的缓冲输出流 |
BufferedReader(Reader in) | 创建一个使用默认大小输入缓冲区的缓冲字符输入流 |
BufferedReader(Reader in,int size) | 创建一个使用size大小输入缓冲区的缓冲字符输入流 |
BufferedWriter(Writer out) | 创建一个使用默认大小输入缓冲区的缓冲字符输出流 |
BufferedWriter(Writer out,int size) | 创建一个使用size大小输入缓冲区的缓冲字符输出流 |
-
常见处理流类 — 缓冲流(Buffered)
-
BufferedInputStream支持其父类的mark和reset方法
-
BufferedWriter提供了readLine方法用于读取一行字符串(以\r或\n分隔)
-
BufferedWriter提供了newLine方法用于写入一个行分隔符
-
对于BufferedOutputStream和BufferdWriter,写出的数据会先在 内存中缓存,使用flush()方法将使内存中的数据立刻写出
-
缓冲流中的方法
-
对象序列化
-
对象序列化概述
-
永久性保存对象,保存对象的字节序列到本地文件中
-
通过序列化对象在网络中传递对象
-
通过序列化在进程间传递对象
-
通过使用ObjectInputStream和ObjectOutputStream类保存和读取对 象的机制叫做序列化机制
-
对象(Object)序列化是指将对象转换为字节序列的过程
-
反序列化则是根据字节序列恢复对象的过程
-
序列化一般用于以下场景:
-
-
支持序列化的接口和类
-
Serializable接口、Externalizable接口
-
ObjectInputStream
-
ObjectOutputStream
-
序列化的过程,是将任何实现了Serializable接口或Externalizable接口的对象通过ObjectOutputStream类提供的相应方法转换为连续的字节数据,这些数据以后仍可通过ObjectInputStream类提供的相应方法被还原为原来的对象状态,这样就可以将对象完成的保存在本 地文件中,或在网络和进程间传递
-
支持序列化的接口和类
-
-
Serializable接口
-
只有一个实现Serializable接口的对象可以被序列化工具存储和 恢复
-
Serializable接口没有定义任何属性或方法。它只用来表示一个类可以被序列化。如果一个类可以序列化,它的所有子类都可 以序列化
-
-
Externalizable接口
-
可以让需要序列化的类实现Serializable接口的子接口Externalizable
-
Externalizable接口表示实现该接口的类在序列化中由该类本身 来控制信息的写出和读入
-
-
ObjectInputStream 类
-
readObject(Object obj)
-
从指定的InputStream中读取对象
-
ObjectInputStream类继承InputStream类,并实现了ObjectInput接口。它负责从流中读取对象
-
构造方法 ObjectInputStream(InputStream in)
-
主要方法
-
-
ObjectOutputStream 类
-
writeObject(Object obj)
-
向指定的OutputStream中写入对象obj
-
ObjectOutputStream类继承OutputStream类,并实现了ObjectOutput接口。它负责向流写入对象
-
构造方法 ObjectOutputStream(OutputStream out)
-
主要方法
-
-
对象序列化的条件
-
serialVersionUID在反序列化过程中用于验证序列化对象的发 送者和接收者是否为该对象加载了与序列化兼容的类。
-
如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致InvalidClassException。
-
该对象类必须实现Serializable接口
-
如果该类有直接或者间接的不可序列化的基类,那么该基类必须 有一个默认的构造器。该派生类需要负责将其基类中的数据写入 流中。
-
建议所有可序列化类都显式声明 serialVersionUID 值。
-
-
transient 关键字
-
transient修饰的属性不进行序列化的操作,起到一定消息屏蔽的 效果
-
被transient修饰的属性可以正确的创建,但被系统赋为默认值。即int类型为0,String类型为null
-
-
注:ObjectInputStream和ObjectOutputStream类不会保存和读写对象中的transient和static类型的成员变量
/ 总结 /
本文主要讲了文件与流IO的介绍和特性,这些知识是后续高阶开发的基础,也是很多软件成长中的瓶颈,只有打好基础,以后我们开发的软件才能越做越大。
往期推荐:
关注我的公众号,学习技术或投稿
长按上图,识别图中二维码即可关注