第十章 输入与输出技术
序言:
1,输入input:程序从外部系统获得数据。读取。
2,输出output:程序将数据输出到外部系统。写入。
10.1 基本概念和I/O入门:
10.1.1数据源:
数据源data source:提供数据的原始媒介。
分为:
源设备:为程序提供数据,一般对应输入流。
目标设备:程序数据的目的地,一般对应输出流。
10.1.2流的概念
流stream 数据源source 数据information 程序 program 目的地dest
1,Java中对文件的操作是以流的方式进行的,
流是Java内存中的一组有序数据序列
数据从源读入到内存中,形成流,这些流可以写入到另外的目的地。
称为流是因为,这个数据序列在不同时刻操作的源的不同部分。
数据源:水箱 。流:水管中流动的水。程序:最终用户。
输入/输出的划分相对于程序而言。
输入流:
通过 流 将 数据源 中的 数据 输送到 程序 中。
输出流:
通过 流 将 程序 中的 数据 输送到 数据源 中。
10.1.3第一个简单的I/O流程序
程序读取数据源的数据时,会通过一个I/O流对象开启一个通向数据源的流,
通过这个I/O流对象的相关方法,可以顺序读取数据源中的数据。
try{
//创建输入流
FileInputStream fis = new FileInputStream("d:/文件名.文件格式");
//一个字节一个字节的读取:
int s1 = fis.read();
System.out.println(s1);
//对象流使用完必须关闭:
fis.close();
}catch(Exception e){
e.printStackTrace;
}
实际开发中根本不知道文件内容,在读取的时候需要结合while循环语句使用。
为了保证出现异常后流的正常关闭,通常需要将流的关闭语句放到finally语句块中,
并且要判断流是不是null.
I/O流的经典写法:
public static void main(String[] args){
FileInputStream fis = null;
try{
fis = new FileInputStream("d:/文件名.文件格式")
StringBuilder sb = new StringBuilder();
int temp = 0;
//当temp=-1时代表已经到了文件结尾,停止读取
while((temp = fis.read() !=-1){
sb.append((char) temp);
}
System.out.println(sb);
}catch(Exception e){
e.printStackTrace();
}finally{
try{
//这种写法保证了即使遇到异常状况,也会关闭流对象。
fis.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
10.1.4 java中流的概念细分
1,按流的方向分:
输入流:数据源-->程序。以InputStream,Reader结尾的流。
输出流 :程序-->目的地。以OutputStream,Writer结尾的流。
2,按处理的数据单元分类:
字节流:以字节为单位获得数据。
命名上以Stream结尾的流一般是字节流,FileInputStream,FileOutputStream.
字符流:以字符为单位获得数据
命名上以Reader/Writer结尾的流一般是字符流,FileReader,FileWriter.
3,按处理对象不同分类:
节点流:直接从数据源或目的地读写数据。
FileInputeStream,FileReader,DateInputeStream.
处理流/包装流:不直接连接到数据源或目的地,是处理流的流,
通过对其他流处理提高程序的性能。
BufferedInputStream,BufferedReader.
节点流处于I/O流的一线,所有操作必须通过他们进行,
处理流可以对节点流进行包装,提高性能或提高灵活性。
10.1.5 Java中I/O流类的体系
1,I/O流体系总结
InputStream&OutputStream:
字节流的抽象类。
Reader&Writer:
字符流的抽象类。
FileInputeStream&FileOutputStream:
节点流,以字节为单位直接操作文件。
ByteArrayInputStream&ByteArrayOutputStream:
节点流,以字节为单位,直接操作字节数组对象。
ObjectInputStream&ObjectOutputStream:
处理流,以字节为单位直接操作对象。
DateInputStream&DateOutputstream:
处理流,以字节为单位直接操作基本数据类型和字符串数据类型
FileReader&FileWriter:
节点流,以字符串为单位,直接操作文本文件(只能读写文本文件)。
BufferedReader&BufferedWriter:
处理流,将Reader/Writer对象进行包装,增加缓存功能,提高读写效率。
BufferedInputStream&BufferedOutputStream:
处理流,将InputStream/Outputstream队形进行包装,增加缓存功能,提高读写效率。
InputStreamReader&OutputStreamWriter:
处理流,将字节流对象转换成字符流对象.
PrintStream:
处理流,将OutputStream进行包装,可以方便的输出字符,更加灵活。
10.1.6 四大I/O抽象类
InputStream&OutputStream和Reader&Writer是所有I/O流的抽象父类。
1,InputStream
该抽象类表示字节输入流的所有类的父类,抽象类不可以实例化,
数据的读取由其子类来实现。
继承自InputStream的流都是用于向程序中输入数据,且数据的单位为字节(8bit)。
常用方法:
int read():读取一个字节数据,并将字节的值以int类型返回,未读出返回-1.
void close():关闭输入流对象,释放相关系统资源。
2,OutputStream
该抽象类表示字节输出流的所有类的父类,抽象类不可以实例化,
输出流接收输出字节,并将这些字节发送到某个目的地。
常用方法:
void write(int n):向目的地中写入一个字节。
void close(); 关闭输入流对象,释放相关系统资源。
3,Reader
读取字符流抽象类,数据单位为字符。
int read():读取一个字符数据,并将字符的值作为int类型返回。未读出返回-1.
void close(); 关闭输入流对象,释放相关系统资源。
4,Writer
写入字符流抽象类,数据单位为字符。
void writer(int n):向输出流中写入一个字符。
void close(); 关闭输入流对象,释放相关系统资源。
10.2 常见流详解
10.2.1 文件字节流: FileInputStream&FileOutputStream
FileInputStream通过字节方式读取文件,适合读取所有类型文件。
FileOutputStream通过字节方式写数据到文件中,适合所有类型文件。
//字符串/字节数组内容写入到文件中
直接写入一个字节数组
void write(byte[] b)
指定从哪个位置开始写,写入长度是多少
void write(byte[] b,int off,int length)
//利用文件流实现文件复制
//将a.text内容,复制到b.text
copyFile("d:/a.text","d:/b.text");
使用文件字节流注意:
1,为了减少对硬盘的读写次数,提高效率,通常设置缓存数组。
读取使用的方法为:read(byte[] b);
写入使用方法为:write(byte[] b,int off,int length) ;
2,程序中如果遇到多个流,每个流都到单独关闭,防止其中一个流出现异常后,
导致其他流无法关闭的情况。
10.2.2 文件字符流:FileReader&FileWriter
1,字节流不能很好的处理Unicode字符,经常出现乱码现象。
处理文本文件时,一般可以使用文件字符流,他以字符为单位。
10.2.3 缓冲字节流:BufferedIntputStream&BufferedOutputStream
BufferedIntputStream&BufferedOutputStream通过内部缓存数组提高操作流的效率。
1, java缓冲流本身不具备I/O流的读取与写入功能,他在节点流或处理流上加上
缓冲功能以提高效率。缓冲流是一种处理流/包装流。
缓冲流对数据源能够频繁高效读写。
缓冲流先将数据缓存起来,当缓存区满或手动刷新时,一次性将数据读取到程序或写入目的地。
2,使用注意:
1,关闭流时应先关闭最外层包装流,"后开启的先关闭"。
2,缓存区默认大小8192字节,也可以使用其他构造器来指定大小。
10.2.4 缓冲字符流:BufferedReader&BUfferedWriter
1, 增加了缓存机制,提高了读写文本的效率,
提供按行读取的方法 readLine().处理文本时可以使用缓冲字符流
2,使用注意:
readLine();方法是BufferedReader特有的方法。
写入一行后要使用newLine()方法换行。
10.2.5 字节数组流:ByteArrayInputStream&ByteArrayOuptStream
1, 用在需要流和数组之间转换的情况。
FileInputStream把文件当作数据源。
ByteArrayInputStream把内存中的"某个字节数组对象"当作数据源。
10.2.6 数据流:DateInputeStream&DateOutputStream
1, 数据流将"基本数据类型和字符串数据类型"作为数据源,
从而允许程序以与机器无关的方式从底层输入/输出流中
操作Java基本数据类型与字符串类型。
他可以对其他节点流或处理流进行包装,增加更灵活,高效的功能。
2,使用数据流时,读取顺序一定要与写入顺序一致,否则不能正常读取数据。
10.2.7 对象流:ObjectInputStream&ObjectOutputstream
1,对象流以"对象为数据源",但必须对传输的对象进行序列化或反序列化操作。
2,对象流可以读写对象和基本数据类型。
使用对象流读取对象时,该对象必须经过序列化与反序列化。
系统提供的类(eg:date)已经实现了序列化接口,自定义类必须手动实现序列化接口。
10.2.8 转换流:InputeStreamReader&OutputStreamReader
1,实现将字节流转换成字符流.
2,使用场景
System.in是字节流对象,代表键盘的输入 ,如果按行接收用户的输入,
就必须用到缓冲字符流BufferedReade特有的方法readLine()。经过观察可以发现,
创建BufferedReader方法的构造器的参数必须是一个Reader对象,这时就可以用上
转换流InpuStreamReader.
System.out是字节流对象,代表输出到显示器。按行读取用户的输入,
并且 将读取的一行字符串直接显示再控制台时,需要使用字符流的write(String str)方法。
所以要使用OutputStreamWriter将字节流转换为字符流。
10.2.9 随意访问文件流:RandomAccessFile
1,作用:
实现一个文件的读和写。
可以访问文件的任意位置。
2,该流需要掌握的三个核心方法
1,RandonAccessFile(String name,String mode);
name用于确定文件。
mode取r(读)或rw(可读写),通过mode可以确定流对文件的访问权限。
2,seek(long a);用于定位流对象读写文件的位置。
a确定读写位置距离文件开头的字节数。
3,getFilePointer();用于获取流的当前读取位置。
10.3 java对象的序列化与反序列化
对象的本质是用于组织和存储数据,对象本身也是数据。
对象存储到硬盘文件中,对象通过网络传输到另外一台电脑。
通过序列化和反序列化实现。
10.3.1 序列化话和反序列化是什么
1,两个进程进行远程通信时以二进制序列的形式在网络上传送。
通过HTTP协议发送字符串信息,也可以在网络上直接发送Java对象。
发送方 将Java对象转化为字节序列(对象的序列化) 才能在网络上传送。
接收方 将字节序列恢复为Java对象(反序列化) 才能正常读取。
2,对象序列化的作用
1,持久化:把对象的字节序列永久保存到硬盘上,通常存放在一个文件中。
eg:休眠的实现,服务器seccion的持久化,hibernate持久化对象。
2,网络通信:在网络上传送对象的字节序列。
eg:服务器之间数据通信,对象传递。
10.3.2 序列化涉及的类和接口
1,ObjectOutputStream对象输出流,
其writeObject(Object obj)方法可对参数指定的obj对象进行序列化,
将得到的字节序列写到一个目标输出流中。
2,ObjectInputStream对象输入流 :
其readObject()方法可以从一个源输入流中读取字节序列,
再将其反序列化为一个对象并返回。
3,只有实现Serializable接口的类的对象才能被序列化,
Serializable接口是一个空接口,只起标记作用。
10.3.3 序列化与反序列化的步骤和实现
static属性不参与序列化。
对象中不想被序列化的属性应使用transient,不能使用static。
为了防止读和写的序列化ID不一致,一般指定一个固定的序列化ID.
10.4 装饰器模式构建I/O流体系
略
10.5 Apache IOUtils和FileUtils的使用
略