目标
- IO的概念
- java.io.file类
- 字节流
- 过滤流
- 对象流
- 对象序列化与反序列化
- 对象克隆
什么是IO
不同介质之间的数据传输其实就是IO
- I ( input ),输入,也称为读
- O( output ),输入,也称为写
常见的IO发生于:
- 程序 ---- 磁盘
- 程序 ---- 程序
- 程序 ---- 内存区
- 本机程序 ---- 其他机器上的程序
- 本机程序 ---- 本机的其他程序
- …
那如何区分是入还是出? 站在程序自身的角度来分析问题.
java.io.File
file 类是对文件系统中文件(file)和 目录(directory)的抽象目录也称为文件夹(folder)
如何知道一个File示例映射到一个物理文件还是物理目录?
- isFile():boolean
- isdirectory():boolean
那如何创建一个File实例?
File f = new File("地址");
如何判断一个文件或者目录是否存在?
f.excits()
如何在磁盘上创建一个不存在的文件呢?
f.createNewFile()
如何在磁盘上创建一个不存在的目录呢?
f.mkdir()
如何在磁盘上创建多级目录呢?
f.mkdirs()
如何删除磁盘上的文件或目录呢?
f.delete()
如何获取文件长度(字节数)?
f.length(): long
如何获取父级和子级?
f.getParent() : String
f.getParentFile() : File
f.list() : String[]
f.listFiles() : File[]
要注意的是,File类并不提供读/写文件内容的API,
要进行内容读写, 要用到流( Stream ).
字节流
流 ( Stream ), 就像两个端点之间的管道一样, 数据通过这个管道进行传输. 管道中流动的是bytes, 所以本质上来讲, 所有的流都基于字节传输. 这称为字节流. 从方向上来说, 可分为输入流( Input Stream )和输出流 ( Output Stream ).
在java.io包中, 字节输入流和输出流的抽象父类分别是:
- inputStream
- read():int // 读一个字节(0-255),如果达到流的尾部返回-1。
- read(byte[] b):int // b作为buffer,最多读取b.length个字节,返回实际读到的字节数,如果到达流的尾部返回- 1。
- read(byte[] ,int offset,int len):int //最多读len个字节,装b中(从offset开始),返回值的含义同上
- OutputSteam
- write(int)//写一个字节到流中
- write(byte[ ] b)//写b.length个字节写到流中
- write(byte[ ] b,int offset,int len )// 把b中从offset开始的len个字节写到流中
- flush()//清空缓冲区
在IO操作过程中,可能产生FileNotFoundException和IOexception,前者继承后者,还有产生EOFException,表示倒了流的末尾
过滤流
过滤流用于对基础流进行功能增强, 例如:
- BufferedInputStream继承了FilterInputStream, 它自带8192字节的缓 冲区, 目的是减少磁盘IO, 提高性能.
- DataInputStream继承了FilterInputStream, 它支持readInt(), readDouble()…等读取流数据的方式.
- …
所有的过滤器都是对基础流的包装, 它们都是这样创建的:
BufferedInputStream bis = new BufferedInputStream(基础流);
对象流与对象序列化
ObjectOutputStream和ObjectInputStream称为对象流, 它们提供如下方法:
- writeObject(obj)
- readObject(): Object
如何创建对象流?
//我要读文件
FileInputStream fis = new FileInputStream( "C:\\dog.dat" );
//包装成对象
ObjectInputStream ois = new ObjectInputStream( fis );
把对象以byte[ ]的形式写入流中,称为序列化(Serialization)
反正,把流中的byte[ ]读取出来,还原为对象,称之为反序列化(DeSeriable)
序列化与反序列化常用于对象缓存,对象克隆,网络中的对象传输. . .
注意事项:
- 要进行序列化的对象所属的类必须实现Serializable接口, 否则抛出NotSerializableException
- 反序化时, 必须保证本地class的SerialVersionUID和流中的SerialVersionUID一致, 否则抛出 InvalidClassException
- 序列化一个对象时, 它的所有属性都要可序列化, 除非添加了transient关键字 ( 序列化过程会忽略transient成 员 )
对象克隆
克隆的应用场景: 有时候, A把一个对象传递给B, 但A不希望B的修改影响这个对象, 所以A把对象克隆一个, 再传给B, B的修 改就无法影响到A手中持有的原始对象.
克隆有两种:
- 浅克隆: 实现标记接口Cloneable, 重写Object.clone()
- 深克隆:
- 方式一: 手工重写Object.clone(), 逐个COPY对象的属性
- 方式二: 使用ByteArrayOutputStream和ObjectOutputStream序列化到byte[], 再使用 ByteArrayInputStream和ObjectInputStream反序列化
浅克隆:
利用序列化实现深克隆:
字符流
很多时候, 介质间传输的是文本消息, 这种情况下, 以byte为单位对流进行读写非常不便, 所以我们需要以char为单位进行读 写的流, 这种流称为字符流.
字符流的抽象类是:
- Read
- Write
常见的Reader有:
- InputStreamReader:称之为转换流,它是字节利用桐乡字符流的桥梁
- BuferedReader:缓冲字符流,它自带8K缓冲区,他包装一个Reader,提供更好的性能。
- FileReader:读文本文件的便捷类,它使用平台默认的charset,不能更改。
- StringReader:为String提供流式操作