1.IO流的基本概念
1.1流的原理
1)在Java程序中,对于数据的输入/输出操作以“流”(stream)方式进行。
2)J2SDK提供了各种各样的“流”类,用以获取不同种类的数据;程序中通过标准的方法输入或输出数据。
3)Java的流类型一般位于java.io包中
1.2流的概念
数据源
- data source.提供原始数据的原始媒介。常见的:数据库、文件、其他程序、内存、网络连接、IO设备。
2)数据源就像水箱,流就像水管中流着的水流,程序就是我们最终的用户。流是一个抽象、动态的概念,是一连串连续动态的数据集合。
2.流的细分和体系_四大抽象类
2.1流的分类
流的方向:
1)输入流:数据源到程序(InputStream、Reader读进来)
2)输出流:程序到目的地(OutPutStream、Writer写出去)
处理数据单元:
1)字节流:按照字节读取数据(InputStream、OutputStream)
2)字符流:按照字符读取数据(Reader、Writer)
注意:输入输出是相对于程序而言,而不是相对于源和目标而言
功能不同:
1)节点流:可以直接从数据源或目的地读写数据。
2)处理流(包装流):不直接连接到数据源或目的地,是其他流进行封装。目的主要是简化操作和提高性能。
节点流和处理流的关系:
1)节点流处于io操作的第一线,所有操作必须通过他们进行;
2)处理流可以对其他流进行处理(提高效率或操作灵活性)。
2.2IO流的体系
1)InputStream和OutputStream
Java语言中最基本的两个字节输入输出类。
其他所有字节输入输出流类都继承自这两个基类。
这两个类都是抽象类,不能创建它们的实例,只能使用它们的子类
2)Reader和Writer
Java语言中最基本的两个字符输入输出类。
其他所有字符输入输出流类都继承自这两个基类
这两个类都是抽象类,不能创建它们的实例,只能使用它们的子类
3.文件字节流
3.1FileInputStream/FileOutputStream
使用FileInputStream读取文件内容
1)abstract int read();
2)int read(byte b[]);
3)int read(byte b[],int off,int len);
4)int available();
5)close();
public class TestInputStream {
public static void main(String[] args) throws IOException {
//(1)数据源于应用程序之间搭建管道
FileInputStream fis = new FileInputStream(new File("D:\\test.txt"));
//(2)从数据源开始向程序中读数据
int count = fis.available();
System.out.println(count);
//中转站比较小,一次读一个字节
//System.out.println(fis.read());
//System.out.println(fis.available());
int buf = 0;//存储读到的字节
int i = 0;
while((buf=fis.read()) != -1) {
i++;
System.out.print((char)buf);
}
System.out.println();
//(3)关闭
fis.close();
System.out.println(i);
}
}
public class TestInputStream2 {
public static void main(String[] args) throws IOException {
//(1)搭桥
FileInputStream fis = new FileInputStream("D:\\test.txt");
//(2)创建大一些的中转站
byte[] buf = new byte[1024];
int len = 0;//用于存储每次读到的实际字节
int i = 0;
while ((len = fis.read(buf)) != -1) {
i++;
System.out.println(new String(buf,0,len));
}
//(3)关闭
fis.close();
System.out.println(i);
}
}
使用FileOutputStream写内容到文件
1)abstract void write(int b);
2)void write(byte b[]);
3)void write(byte b[],int off,int len);
4)void flush();
5)void close();
public class TestFileOutputStream {
public static void main(String[] args) {
//(1)搭桥
FileOutputStream fos = null;
try {
fos = new FileOutputStream("D:\\a.txt",true);//true如果磁盘上有文件,而且文件有内容,将在原来的内容的基础上进行追加
//(2)写数据,一次写一个字节
//fos.write(97);
//(3)一次写多个字节
byte[] buf = "helloworld".getBytes();
fos.write(buf);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//(3)关闭
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
4.使用字节流实现文件复制
4.1文件复制的原理
public class TestFileCopy {
public static void main(String[] args) {
//数据源是文件
FileInputStream fis = null;
//目的地
FileOutputStream fos = null;
try {
fis = new FileInputStream("D:\\test.txt");
fos = new FileOutputStream("D:\\test2.txt");
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf))!=-1) {
fos.write(buf, 0, len);
}
/*
int b = 0;
while ((b = fis.read())!=-1) {
fos.write(b);
}
*/
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if(fis != null) {
fis.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if(fos != null) {
fos.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
5.文件字符流
5.1Reader/Writer
使用Reader读取文件内容
1)int read();
2)int read(char[] cbuf)
3)int read(char[] cbuf,int off,int len);
4) int available();
5)close();
public class TestFileReader {
public static void main(String[] args) throws IOException {
//(1)搭桥
FileReader reader = new FileReader("D:\\test.txt");
//(2)读取
//int b = reader.read();//读到的字符的int类型 数据
//System.out.println((char)b);
/*
int b = 0;
while ((b = reader.read()) != -1) {
System.out.print((char)b);
}
*/
char[] ch = new char[1024];
int len = 0;
while ((len = reader.read(ch)) != -1) {
System.out.println(new String(ch,0,len));
}
reader.close();
}
}
使用Writer写内容到文件
1)void write(int c);
2)void write(char[] cbuf);
3)abstract void write(char[] cbuf,int off,int len);
4)void write(String str);
5) abstract void flush();
6)void close();
public class TestWriter {
public static void main(String[] args) {
//创建对象
FileWriter write = null;
try {
write = new FileWriter("D:\\b.txt");
//写数据
write.write("你好吗?");//写到了缓冲区中
write.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//关闭
if (write != null) {
try {
write.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
6.缓冲字节流_缓冲字符流
6.1缓冲字节流
BufferedInputStream和BufferedOutputStream
FileInputStream和FileOutputStream是节点流
BufferedInputStream和BufferedOutputStream是处理流(包装流)
- 读文件和写文件都使用了缓冲区,减少了读写次数,从而提高了效率
- 当创建这两个缓冲流的对象时,会创建内部缓冲数组,缺省使用32字节大小的缓冲区
- 当读取数据时,数据按块读入缓冲区,其后的读操作则直接访问缓冲区
- 当写入数据时,首先写入缓冲区,当缓冲区满时,其中的数据写入所连接的输出流。使用方法flush()可以强制将缓冲区的内容全部写入输出流。
- 关闭流的顺序和打开流的顺序相反。只要关闭高层流即可,关闭高层流其实关闭了底层节点流。
- Flush的使用:手动将buffer中内容写入文件。
public class TestCopy {
public static void main(String[] args) {
//(1)数据源
FileInputStream fis = null;
//(2)目的地
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
fis = new FileInputStream("D:\\jdk api 1.8_google.CHM");
fos = new FileOutputStream("D:\\jdk api 1.8_google2.CHM");
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
byte[] b = new byte[1024];
int len = 0;
long start = System.currentTimeMillis();
while ((len=bis.read(b)) != -1) {
bos.write(b, 0, len);
}
long end = System.currentTimeMillis();
System.out.println("文件复制一共用了:" + (end-start) + "毫秒");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
//关闭
try {
if(bos != null) {
bos.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if (bis != null) {
bis.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
6.2缓冲字符流
BufferedReader
readLine() 读取一个文本行的数据
BufferedWriter
newLine():写入一个行分隔符
使用缓冲字符流是复制文本文件常用的方式
public class TestBuffered {
public static void main(String[] args) {
//缓冲字符流
BufferedReader br = null;
BufferedWriter bw = null;
try {
br = new BufferedReader(new FileReader("D:\\a.txt"));
bw = new BufferedWriter(new FileWriter("D:\\copya.txt"));
String line = null;//用于存储读到的字符串
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
bw.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if (bw != null) {
bw.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if (br != null) {
br.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
7.转换流
7.1InputStreamReader和OutputStreamWriter
处理流
用于将字节流转化成字符流,字符流与字节流之间的桥梁。
InputStreamReader的作用是把InputStream装换成Reader
OutputStreamWriter的作用是把OutputStream装换成Writer
存在将字节流装换成字符流的装换流,因为字符流操作文本更简单
不存在把字符流装换成字节流的装换流,因为没有必要
System.in代表标准输入,即键盘输入,是InputStream的实例
public class Test {
public static void main(String[] args) {
//任务需求,从键盘获取数据,写入磁盘文件
//(1)数据源是标准的输入设备,键盘System.in
//(3)提高读取效率
BufferedReader br = null;
//(4)提高写入效率
BufferedWriter bw = null;
try {
InputStream is = System.in;
//(2)需要使用转换流,装换成字符流
InputStreamReader isr = new InputStreamReader(is,"gbk");
br = new BufferedReader(isr);
bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:\\systein.txt"),"gbk"));
//(5)写入磁盘文件
String line = null;
while (!"over".equals(line=br.readLine())){
bw.write(line);
bw.newLine();
bw.flush();
}
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if (bw != null) {
try {
bw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (br != null) {
try {
br.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
8.打印流
8.1PrintStream
1)PrintStream提供了一系列的print()和println(),可以实现将基本数据类型格式化成字符串输出。对象类型先调用toString(),然后输出该方法返回的字符串。
2)System.out就是PrintStream的一个实例,代表显示器
3)System.err也是PrintStream的一个实例,代表显示器
4)PrintStream的输出功能非常强大,通常需要输出文本内容,都可以将输出流包装成PrintStream后进行输出。
5)PrintSteam的方法都不抛出IOException
8.2PrintWriter
1)PrintStream的对应字符流,功能相同,方法对应。
2)PrintWriter的方法也不抛出IOException
3)复制文件时可以使用PriWriter代替BufferedWriter完成,更简单。
public class Test {
public static void main(String[] args) throws IOException {
//PrintStream ps = System.out;
//PrintStream ps = System.err;
//PrintStream ps = new PrintStream(new FileOutputStream("D:\\print.txt"));
PrintWriter ps = new PrintWriter(new FileOutputStream("D:\\print1.txt"));
//无需类型转换,自动转成String类型
ps.println("hello");
ps.println(true);
ps.println(19);
ps.println(98.5);
ps.println(new Date(1000));
ps.flush();
ps.close();
//只能写入字符串类型
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\a.txt"));
bw.write("helloworld");
bw.flush();
bw.close();
}
}
9.数据流
9.1DataInputStream和DataOutputStream
1)提供了可以存取所有Java基础类型数据(如:int,double等)和String的方法。
2)处理流,只针对字节流,二进制文件
3)输入流链和输出流链
4)注意:只要关闭上层流即可
public class Test {
public static void main(String[] args) throws IOException {
write();
read();
}
//读数据的方法
public static void read() throws IOException {
//数据源
FileInputStream fis = new FileInputStream(new File("D:\\data.txt"));
//
BufferedInputStream bis = new BufferedInputStream(fis);
//
DataInputStream dis = new DataInputStream(bis);
System.out.println(dis.readInt());
System.out.println(dis.readDouble());
System.out.println(dis.readBoolean());
System.out.println(dis.readChar());
System.out.println(dis.readUTF());
dis.close();
}
//写数据的方法
public static void write() throws IOException {
/*
//目的地
FileOutputStream fos = new FileOutputStream(new File("D:\\data.txt"));
//缓冲流提高写入效率
BufferedOutputStream bos = new BufferedOutputStream(fos);
//数据流,增加对java基本基本数据类型和String的处理
DataOutputStream dos = new DataOutputStream(bos);
*/
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(new File("D:\\data.txt"))));
//写入数据
dos.writeInt(98);
dos.writeDouble(98.5);
dos.writeBoolean(true);
dos.writeChar('a');
dos.writeUTF("helloworld");
//关闭流
if(dos != null) {
dos.close();
}
}
}
10.对象流
10.1对象xu序列化(Serialization)
ObjectOutputStream—>序列化—>写对象,将对象以“二进制/字节”的形式写到(文件)
ObjectInputStream —>反序列化—>读对象
将Java对象转换成字节序列(IO字节流)
对象反序列化(DeSerialization)
从字节序列中恢复Java对象
10.2为什么序列化
序列化以后的对象可以保存到磁盘上,也可以在网络上传输,使得不同的计算机可以共享对象。(序列化的字节序列是平台无关的)
10.3对象序列化的条件
只有实现了Serializable接口的类的对象才可以被序列化。
Serializable接口中没有任何的方法,实现该接口的类不需要实现额外的方法。
如果对象的属性时对象,属性对应类也必须实现Serializable接口
10.4如何实现序列化
创建ObjectOutputStream对象
调用writeObject()输出对象
10.5如何实现反序列化
创建ObjectInputStream对象
调用readObject()读取对象
public class Person implements Serializable{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class Test {
public static void main(String[] args) {
//write();
read();
}
//读对象的方法
public static void read() {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("D:\\object.txt"));
System.out.println(ois.readInt());
System.out.println(ois.readUTF());
Person p = (Person)ois.readObject();
System.out.println(p);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(ois != null) {
try {
ois.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//写对象的方法
public static void write() {
//创建对象流对象
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("D:\\object.txt"));
oos.writeInt(98);
oos.writeUTF("hello");
oos.writeObject(new Person("marry",18));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(oos != null) {
try {
oos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
11.序列化和反序列化
11.1序列化与反序列化
1)序列化能保存的元素
a)只能保存对象的非静态成员变量
b)不能保存任何成员方法和静态的成员变量
c)不保存transient成员变量
d)如果一个对象的成员变量是一个对象,这个对象的成员变量也会保存
e)序列化保存的只是变量的值,对于变量的任何修饰符,都不能保存
2)使用对象流把一个对象写到文件时不仅保证该对象时序列化的,而且该对象的成员对象也必须是可序列化的
3)如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作将会失败,并且会抛出一个NotSerializableException。我们可以将这个引用标记为transient,那么对象仍然可以序列化。
11.2对象序列化注意事项
1)同一个对象多次序列化的处理
a)所有保存到磁盘中的对象都有一个序列化编号
b)序列化一个对象中,首先检查该对象是否已经序列化过
c)如果没有,进行序列化
d)如果已经序列化,将不再重新序列化,而是输出编号即可
2)如果不希望某些属性序列化,或不希望出现递归序列
a)为属性添加transient关键字(完成排除在序列化之外)
b)自定义序列化(不仅可以决定哪些属性不参加序列化,还可以定义属性具体如何序列化)
3)序列化版本不兼容
a)修改了实例属性后,会影响版本号,从而导致反序列化不成功
b)解决方案:为Java对象指定序列化版本号serialVersionUID
public class Student implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private int age;
public static String school;
private transient String pwd;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public Student(String name, int age, String pwd) {
super();
this.name = name;
this.age = age;
this.pwd = pwd;
}
public Student() {
super();
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", pwd=" + pwd + "]" + "School =" + school;
}
}
public class Test {
public static void main(String[] args) {
//write();
read();
}
public static void read() {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("D:\\Object2.txt"));
Student stu = (Student)ois.readObject();
System.out.println(stu);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if(ois != null) {
try {
ois.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void write() {
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("D:\\Object2.txt"));
Student stu = new Student("marry",18,"888888");
Student.school = "java";
oos.writeObject(stu);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public class Classes implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private ArrayList<Student> al;
private String school;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ArrayList<Student> getAl() {
return al;
}
public void setAl(ArrayList<Student> al) {
this.al = al;
}
public Classes(String name, ArrayList<Student> al) {
super();
this.name = name;
this.al = al;
}
public Classes() {
super();
}
@Override
public String toString() {
return "Classes [name=" + name + ", al=" + al + "]";
}
}
public class TestClasses {
public static void write() {
ArrayList<Student> al = new ArrayList<Student>();
al.add(new Student("marry",18,"888888"));
al.add(new Student("jack",20,"123456"));
al.add(new Student("lili",22,"654321"));
Classes cl = new Classes("1班",al);
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("D:\\classes.txt"));
oos.writeObject(cl);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if(oos != null) {
try {
oos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void read() {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("D:\\classes.txt"));
Classes cla = (Classes) ois.readObject();
System.out.println(cla);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
//write();
read();
}
}
12.文件夹的复制
12.1复制文件夹
字节流 字符流
BufferedInputStream,BufferedOutputStream FileInputStream,FileOutputStream
问题分解
1)复制一个文件
2)指定目录下的所有文件
3)指定目录下的所有文件及子目录下的所有文件
public class TestCopy {
public static void main(String[] args) {
/*File srcFile = new File("D:\\360极速浏览器下载\\太子妃升职记.torrent");
File targetFile = new File("D:\\太子妃升职记.torrent");
copyFile(srcFile,targetFile);
*/
File srcDir= new File("D:\\360极速浏览器下载");
File targetDir = new File("C:\\360极速浏览器下载");
copyDir(srcDir,targetDir);
}
public static void copyDir(File srcDir,File targetDir) {
if (!targetDir.exists()) {
targetDir.mkdir();//如过目的地不存在,则需要使用File类的方法进行创建
}
File[] files = srcDir.listFiles();//获取指定目录下的所有File对象
for (File file : files) {
if (file.isFile()) {
copyFile(new File(srcDir+"\\"+file.getName()),new File(targetDir+"\\"+file.getName()));
}else {
copyDir(new File(srcDir+"\\"+file.getName()),new File(targetDir+"\\"+file.getName()));
}
}
}
public static void copyFile(File srcFile,File targetFile) {
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream(new FileInputStream(srcFile));
bos = new BufferedOutputStream(new FileOutputStream(targetFile));
byte[] buf = new byte[1024];
int len = 0;
while ((len=bis.read(buf)) != -1) {
bos.write(buf, 0, len);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
13.字节数组流
13.1ByteArrayInutStream 和 ByteArrayOutputStream
1)数据源或目的地为:字节数组
2)只有字节流,没有字符流
3)节点流
public class Test {
public static void main(String[] args) {
byte[] buf = write();
read(buf);
}
public static void read(byte[] buf) {
ObjectInputStream ois = null;
try {
ByteArrayInputStream bais = new ByteArrayInputStream(buf);
ois = new ObjectInputStream(bais);
System.out.println(ois.readInt());
System.out.println(ois.readDouble());
System.out.println(ois.readChar());
System.out.println(ois.readBoolean());
System.out.println(ois.readObject());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if(ois != null) {
try {
ois.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static byte[] write() {
//创建字节数组流对象
ByteArrayOutputStream bas = null;
ObjectOutputStream oos = null;
try {
bas = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bas);
oos.writeInt(98);
oos.writeDouble(98.5);
oos.writeChar('a');
oos.writeBoolean(true);
oos.writeObject(new Date(1000));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return bas.toByteArray();
}
}
14.设计模式_装饰器模式
14.1装饰器模式Decorator
职责:动态的为一个对象增加新的功能
装饰模式是一种用于代替继承的技术,无须通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀。
实现细节
1)抽象构件角色 ICar
2)具体的构件角色 Car
3)装饰器角色 SuperCar
4)具体的装饰器角色 FlyCar、WaterCar、AICar
public interface ICar {
void move();
}
public class Car implements ICar{
@Override
public void move() {
System.out.println("汽车可以在陆地上行驶");
}
}
public class SuperCar implements ICar{
private ICar car;
public SuperCar(ICar car) {
super();
this.car = car;
}
@Override
public void move() {
// TODO Auto-generated method stub
car.move();
}
}
public class FlyCar extends SuperCar{
public FlyCar(ICar car) {
super(car);
// TODO Auto-generated constructor stub
}
public void move() {
super.move();
this.fly();
}
public void fly() {
System.out.println("汽车可以飞行,因为有翅膀");
}
}
public class WaterCar extends SuperCar{
public WaterCar(ICar car) {
super(car);
// TODO Auto-generated constructor stub
}
public void move() {
super.move();
this.water();
}
public void water() {
System.out.println("汽车可以潜水");
}
}
public class AICar extends SuperCar{
public AICar(ICar car) {
super(car);
// TODO Auto-generated constructor stub
}
@Override
public void move() {
// TODO Auto-generated method stub
super.move();
this.autoDrive();
}
private void autoDrive() {
// TODO Auto-generated method stub
System.out.println("可以自动驾驶");
}
}
public class Test {
public static void main(String[] args) {
ICar car = new Car();
car.move();
System.out.println("\n为汽车增加新的功能");
FlyCar fly = new FlyCar(car);
fly.move();
System.out.println("\n再为汽车增加自动驾驶的功能");
AICar ai = new AICar(fly);
ai.move();
AICar ai2 = new AICar(new FlyCar(new Car()));
ai2.move();
System.out.println("各种组合");
WaterCar water=new WaterCar(new FlyCar(new AICar(new Car())));
water.move();
}
}
优点
1)扩展对象功能,比继承灵活,不会导致类个数急剧增加
2)可以对一个对象进行多次装饰,创建出不同行为的组合,得到的功能更强大的对象。
3)具体构建类和具体装饰类可以独立变化,用户可以根据需要自己增加新的具体构建子类和具体装饰子类
缺点
1)产生很多小对象。大量小对象占据内存,一定程度上影响性能。
2)装饰模式易于出错,调试排查比较麻烦
IO流实现细节
1)抽象构件角色 InputStream,OutputStream,Reader,Writer
2)具体构件角色 FileInputStream,FileOutputStream
3)装饰器角色 FilterInputStream,FilterOutputStream 持有一个抽象构件的引用
4)具体装饰角色 BufferedInputStream,BufferedOutputStream 等
16.Apache IOUtils的使用_Apache FileUtils的使用
16.1IOUtils 与 FileUtils
**Commons IO 是 apache 的一个开源的工具包,封装了 IO 操作的相关类,使用 Commons IO 可以很方便的读写文件, **
FileUtils 中提供了许多设计文件操作的 已封装好的方 法。
IOUtils 则是提供了读写文件的方法 .
16.2IOUtils 工具类操作的相关方法
String IOUtils.toString(InputStream input)传入输入流对象 返回字符串
16.3FileUtils 工具类操作的相关方法
- String FileUtils.readFileToString(File file,String encoding)
- FileUtils.writeStringToFile(File file,String data,String encoding)读写文件
- FileUtils.copyFile(File srcFile,File destFile)复制文件
- )FileUtils.copyURLToFile(URL source,File destination)复制 url 对象到指定文件
public class TestIOUtils {
public static void main(String[] args) throws FileNotFoundException, IOException {
//读数据
String str = IOUtils.toString(new FileInputStream("D:\\123.txt"));
System.out.println(str);
//写数据
IOUtils.write(str, new FileOutputStream("D:\\456.txt"));
//复制文件中的内容
IOUtils.copy(new FileInputStream("D:\\123.txt"), new FileOutputStream("D:\\789,txt"));
}
}
public class TestFileUtils {
public static void main(String[] args) throws IOException {
FileUtils.copyFile(new File("D:\\123.txt"),new File("D:\\101.txt"));
URL url = new URL("https://www.baidu.com");
FileUtils.copyURLToFile(url, new File("D:\\baidu.html"));
}
}