IO技术
-
基本概念
- 数据源:
- 源设备:为程序提供数据,输入流
- 目标设备:程序数据目的地,输出流
- 流的概念
- 流是一个抽象的、动态的概念,是一连串动态数据集合。
- 输入/输出流的划分是相对程序而言的,并不是数据源。
- 流是一个抽象的、动态的概念,是一连串动态数据集合。
- 使用流读取文件内容
import java.io.*; public class TestIO2 { public static void main(String[] args) { FileInputStream fis = null; try { fis = new FileInputStream("d:/a.txt"); // 内容是:abc 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 { //这种写法,保证了即使遇到异常情况,也会关闭流对象。 if (fis != null) { fis.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
- JAVA中流的概念细分
- 按流的方向分类:
- 输入流:数据源流向程序(InputStream、Reader结尾的流)
- 输出流:程序流向目的地(OutputStream、Writer结尾的流)
- 按处理数据的单元分类
- 字节流:以字节为单位获取数据,一般以Stream结尾
- 字符流:以字符为单位获取数据,以Reader、Writer结尾
- 按处理对象不同分类
- 节点流:可以直接从数据源或目的地读写数据
- 处理流:不直接读写数据
- 按流的方向分类:
- java中IO流类的体系
- InputStream/OutputStream—》字节流抽象类
- Reader/Writer—》字符流抽象类
- FileInputStream/FileOutputStream—》节点流:以字节为单位直接操作“文件”。
- ByteArrayInputStream/ByteArrayOutputStream—》 节点流:以字节为单位直接操作“字节数组对象”。
- ObjectInputStream/ObjectOutputStream—》处理流:以字节为单位直接操作“对象”。
- DataInputStream/DataOutputStream—》处理流:以字节为单位直接操作“基本数据类型与字符串类型”。
- FileReader/FileWriter—》节点流:以字符为单位直接操作“文本文件”
- BufferedReader/BufferedWriter—》 处理流:将Reader/Writer对象进行包装,增加缓存功能,提高读写效率。
- BufferedInputStream/BufferedOutputStream—》处理流:将InputStream/OutputStream对象进行包装,增加缓存功能,提高 读写效率。
- InputStreamReader/OutputStreamWriter—》 处理流:将字节流对象转化成字符流对象
- PrintStream—》 处理流:将OutputStream进行包装,可以方便地输出字符,更加灵活。
- 四大IO抽象类
- InputSteam
- FileInputStream
- ByteArrayInutStream
- BufferedInputStream
- DataInputStream
- ObjectInputStream
- OutputStream
- FileOutputStream
- ByteArrayOutputStream
- BufferedOutputStream
- DataOutputStream
- ObjectOutputStream
- PrintStream
- Reader
- FileReader
- BufferedReader
- InputStreamReader
- Writer
- FileWriter
- BufferedWriter
- OutputStreamWriter
- InputSteam
- 数据源:
-
文件字节流
- FileInputStream通过字节的方式读取文件,适合读取所有类型的文件。
- FileOutputStream通过字节的方式写数据到文件中。
-
注意:
- 为了减少对于硬盘的读写次数,提高效率,通常使用缓存数组
- 程序中的多个流都要单独关闭。
-
缓存字节流
- java的缓存字节流本身不具有IO的读写功能,只能在别的流上加缓存功能提高效率。做装饰器使用
- 注意:
- 在关闭流时,应该先关闭最外层的包装流
- 缓存的大小默认是8192字节,也可以使用构造方法自己指定大小。
- readLine()方法是BufferedReader特有的方法,可以对文本文件进行更加方便的读取操作。
- 写入一行后记得使用newLine()方法换行。
-
数据流
注意 : 使用数据流时,读取顺序一定要与写入顺序一致,否则不能正确读取数据。
-
对象流
-
ObjectInputStream/ObjectOutputStream是以“对象”为数据源,但是必须将传输的对象进行序列化和反序列化操作。
-
注意:
- 对象流不仅可以读写对象,还可以读写基本数据类型
- 使用对象流读写对象时,该对象必须序列化和反序列化
- 系统提供的类已经实现序列化接口,自定义类必须手动实现序列化接口
-
-
转化流
- InputStreamReader/OutputStreamWriter用来实现将字节流转化为字符流。
-
序列化和反序列化
-
定义
- 把Java对象转换为字节序列的过程称为对象的序列化
- 把字节序列恢复为Java对象的过程称为对象的反序列化
-
序列化的作用
- 持久化:把对象的字节序列永久保存在硬盘中,通常放在一个文件中。
- 网络通信:在网络上传送对象字节序列。
-
序列化涉及的类和接口
- ObjectOutputStream:对象输出流,writeObject(Object object)方法可以对参数指定的object对象进行序列化,把得到的字节序列写到一个目标输出流中。
- ObjectInputStream代表对象输入流,readObject()方法可以从一个源输入流读取字节序列,通过反序列化操作转化为一个对象,返回值。
- 注意:只有实现了Serializable接口的类的对象才能被序列化。
-
序列化/反序列化实现过程中需要注意的点
- static属性不参与序列化
- 对象中的某些属性如果不想被序列化,不能使用static,而是使用transient修饰。
- 为了防止读和写的序列化ID不一致,一般指定一个固定的序列化ID。
-
-
装饰器模式
装饰器是GOF23种设计模式较为常用的一种模式。可以实现对原有类的包装和修饰,使新的类具有更强的功能。
class Iphone {
private String name;
public Iphone(String name) {
this.name = name;
}
public void show() {
System.out.println("我是" + name + ",可以在屏幕上显示");
}
}
class TouyingPhone {
public Iphone phone;
public TouyingPhone(Iphone p) {
this.phone = p;
}
// 功能更强的方法
public void show() {
phone.show();
System.out.println("还可以投影,在墙壁上显示");
}
}
public class TestDecoration {
public static void main(String[] args) {
Iphone phone = new Iphone("iphone30");
phone.show();
System.out.println("===============装饰后");
TouyingPhone typhone = new TouyingPhone(phone);
typhone.show();
}
}
-
FileUtils的常用方法
方法名 作用 cleanDirectory 清空目录,但不删除目录。 contentEquals 比较两个文件的内容是否相同。 copyDirectory 将一个目录内容拷贝到另一个目录。可以通过FileFilter过滤需要拷贝的 文件。 copyFile 将一个文件拷贝到新地址 copyFileToDirectory 将一个文件拷贝到某个目录下 copyInputStreamToFile 将一个输入流中的内容拷贝到某个文件 deleteDirectory 删除目录 deleteQuietly 删除文件 listFiles 列出指定目录下的所有文件 openInputSteam 打开指定文件的输入流 readFileToString 将文件内容作为字符串返回 readLines 将文件内容按行返回到一个字符串数组中 size 返回文件或目录大小 write 将字符内容直接写到文件中 writeByteArrayToFile 将字节数组内容写到文件中 writeLines 将容器中的元素的toString方法返回的内容依次写入文件中 writeStringToFile 将字符串内容写到文件中 -
IOUtils的常用方法
方法名 作用 buffer 将传入的流进行包装,变成缓冲流。并可以通过参数指定缓冲大小。 closeQueitly 关闭流。 contentEquals 比较两个流中的内容是否一致。 copy 将输入流中的内容拷贝到输出流中,并可以指定字符编码。 copyLarge 将输入流中的内容拷贝到输出流中,适合大于2G内容的拷贝。 lineIterator 返回可以迭代每一行内容的迭代器 read 将输入流中的部分内容读入到字节数组中 readFully 将输入流中的所有内容读入到字节数组中 readLine 读入输入流内容中的一行 toBufferedInputStream,toBufferedReader 将输入转为带缓存的输入流 toByteArray,toCharArray 将输入流的内容转为字节数组、字符数组 toString 将输入流或数组中的内容转化为字符串 write 向流里面写入内容 writeLine 向流里面写入一行内容 -
作业
一、选择题
1.使用Java IO流实现对文本文件的读写过程中,需要处理下列(B )异常。(选择一项)
A.ClassNotFoundException
B.IOException
C.SQLException
D.RemoteException
2.在Java的IO操作中,( )方法可以用来刷新流的缓冲。(选择两项)
A.void release()
B.void close()
C.void remove()
D.void flush()
3.在Java中,下列关于读写文件的描述错误的是( )。(选择一项)
A.Reader类的read()方法用来从源中读取一个字符的数据
B.Reader类的read(int n )方法用来从源中读取一个字符的数据
C.Writer类的write(int n)方法用来向输出流写入单个字符
D.Writer类的write(String str)方法用来向输出流写入一个字符串
4.阅读下列文件定入的Java代码,共有( )处错误。(选择一项)
import java.io.*;
public class TestIO {
public static void main(String []args){
String str ="文件写入练习";
FileWriter fw = null; //1
try{
fw = new FileWriter("c:\mytext.txt"); //2
fw.writerToEnd(str); //3
}catch(IOException e){ //4
e.printStackTrace();
}finally{
//此处省略关闭流
}
}
}
A.0
B.1
C.2
D.3
5.分析如下Java代码,有标注的四行代码中,有错误的是第( )处。(选择一项)
import java.io.FileWriter;
import java.io.IOException;
public class Test {
public static void main(String[ ] args) {
String str = "Hello World";
FileWriter fw = null;
try {
fw = new FileWriter("c:\\hello.txt"); // 1
fw.write(str); // 2
} catch (IOException e) {
e.printStackTrace(); // 3
} finally {
fw.close(); // 4
}
}
}
A.1
B.2
C.3
D.4
二、简答题
-
说出本章最基本的四个抽象类及他们的区别?
-
读入读出流的数据必须是按照顺序,依次读出吗? 如果我想读取某个文件指定位置,如何做到?
-
想copy一个文本数据,使用哪些流? 如果考虑效率问题,使用那些流较好?
-
对象的序列化接口的特点。
-
想把一个字节流转化成字符流,使用什么流?
三、编码题
-
实现字节数组和任何基本类型和引用类型执行的相互转换
提示:使用ByteArrayInutStream和ByteArrayOutputStream。
-
复制文件夹d:/sxtjava下面所有文件和子文件夹内容到d:/sxtjava2。
提示:涉及单个文件复制、目录的创建、递归的使用
-
使用IO包中的类读取D盘上exam.txt文本文件的内容,每次读取一行内容,将每行作为一个输入放入ArrayList的泛型集合中并将集合中的内容使用加强for进行输出显示。