声明:由于学习所用环境为JDK1.8,所有java代码均在JDK1.8环境中测试通过,如果环境发生变化,可能会有错误发生!
一.内存流
1、内存流主要用来操作内存
输入输出可以把文件当做输入源,也可以把内存当做输入源。
ByteArrayInputStream:负责把内存中的数据读入程序中;
ByteArrayOutputStream:负责把程序中的数据写入内存中。
注意:由于内存流操作的是内存,没有占用系统内存和使用系统资源,所以不需要,也不需要抛出异常。
2、内存流操作示意图
3、ByteArrayOutputStream获取数据的方式
(1) public byte[] toByteArray()
创建一个新分配的字节数组。它的大小是这个输出流的当前大小和缓冲区的有效内容的副本
(2)public String toString()
使用该平台的默认字符集将缓冲区的内容转换为字符串
package memory;
import java.io.*;
public class BostoByteArray {
public static void main(String[] args) {
File srcFile=new File("e:"+File.separator+"picture"+File.separator+"6.jpg");
File destFile=new File("c:"+File.separator+srcFile.getName());
InputStream input=null;
OutputStream out=null;
ByteArrayOutputStream bos=new ByteArrayOutputStream();
try {
input=new FileInputStream(srcFile);
out=new FileOutputStream(destFile);
int len=0;
byte[] b=new byte[1024]; //定义缓冲区
while((len=input.read(b))!=-1){
bos.write(b,0,len); //不断写入内存中
}
byte[] array=bos.toByteArray(); //传建一个新分配的字节数组,它的大小是输出流的当前大小和缓冲区大小的副本
out.write(array); //一次性写到磁盘
System.out.println("复制成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
package memory;
import java.io.*;
public class BostoString {
public static void main(String[] args) {
ByteArrayOutputStream bos=new ByteArrayOutputStream();
try {
bos.write("hello world西安理工大学".getBytes("utf-8"));
System.out.println(bos.toString("utf-8"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
二.打印流
1、打印流提供了打印方法,可以将各种数据类型原样打印,可以操作输出流和文件
(1)PrintStream
提供操作字节功能
如果包装的是缓冲流可设置自动flush
可设置字符集
(2)PrintWriter
没有操作字节功能
内部有缓冲区,即使自动刷新设置为true
可设置字符集
2、打印流的构建方法
(1)PrintStream的构造方法:
public PrintStream(File file)
public PrintStream(OutputStream out)
(2)PrintWriter的构造方法
public PrintWriter(File file)
public PrintWriter(Writer out)
public PrintWriter(OutputStream out)
package print;
import java.io.*;
public class PrintStreamDemo {
public static void main(String[] args) {
File f=new File("d:"+File.separator+"test.txt");
PrintStream ps=null;
OutputStream out=null;
BufferedOutputStream bos=null;
try {
out=new FileOutputStream(f);
bos=new BufferedOutputStream(out);
ps=new PrintStream(bos);
ps.println('M');
ps.println(true);
ps.println(9);
ps.flush();
System.out.println("写入成功!");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
package print;
import java.io.*;
public class PrintWriterDemo {
public static void main(String[] args) {
File f=new File("d:"+File.separator+"test.txt");
PrintWriter pw=null;
try {
pw=new PrintWriter(f);
pw.println('M');
pw.println(false);
pw.println("中国");
pw=new PrintWriter(new FileWriter(f));
pw.println(true);
pw=new PrintWriter(new FileOutputStream(f));
pw.println("hello java");
} catch (Exception e) {
e.printStackTrace();
}
}
}
三.对象流、序列化与反序列化
1、相关类:
ObjectOutputStream(用于序列化)
ObjectInputStream(用于反序列化)
使用对象流可以实现对象的序列化与反序列化操作
序列化的目的:易于保存,易于传输。
2、序列化与反序列化的过程
3、序列化的步骤
4、反序列化的步骤
package serial;
import java.io.*;
public class SerialDemo {
public static void main(String[] args) {
Student student=new Student("李丽",18,"女",89.0);
File file=new File("d:"+File.separator+"student.txt");
OutputStream out=null;
ObjectOutputStream oos=null;
try {
out=new FileOutputStream(file);
oos=new ObjectOutputStream(out);
oos.writeObject(student);
System.out.println("序列化成功!");
} catch (Exception e){
e.printStackTrace();
}
}
}
package serial;
import java.io.*;
public class SerialDe {
public static void main(String[] args) {
File file=new File("d:"+File.separator+"student.txt");
InputStream input=null;
ObjectInputStream ois=null;
OutputStream out=null;
try {
input=new FileInputStream(file);
ois=new ObjectInputStream(input);
Student stu=(Student)ois.readObject();
System.out.println(stu);
System.out.println("反序列化完成");
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter
(new FileOutputStream("e:"+File.separator+"abc.txt")));
String str=stu.toString();
bw.write(str);
bw.flush();
System.out.println("保存成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
四、RandomAccessFile
1、(1)直接继承Object类
(2)主要功能是完成随机读写功能,可以读取指定位置的内容
(3)构造方法:
public RandomAccessFile(File file,String mode)
public RandomAccessFile(String name,String mode)
(4)只能操作文件
2、文件的打开模式(mode):
“r” 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。
“rw” 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。
3、RandomAccessFile常用方法
(1)void seek(long pos)设置文件指针偏移量,在该位置准备开始读写。
(2)int skipBytes(int n)尝试跳过输入的 n 个字节并丢弃跳过的字节.返回实际跳过的字节数
(3)long getFilePointer()获取此文件中的当前偏移量
(4)long length()返回此文件的长度。
package raf;
import java.io.File;
import java.io.RandomAccessFile;
public class RafDemo {
public static void main(String[] args) {
File f=new File("d:"+File.separator+"test.txt");
RandomAccessFile raf=null;
try {
raf=new RandomAccessFile(f, "rw");
raf.writeBoolean(true); //一个字节
raf.writeChars("西安理工大学"); //一个字符占两个字节
raf.writeChar('M'); //一个字符占两个字节
raf.seek(13);
System.out.println("当前指针位置为"+raf.getFilePointer());
System.out.println(raf.readChar());
System.out.println("写入成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
(5)void write(int)向此文件写入指定的字节。
(6)void write(byte[])将 b.length 个字节从指定 byte 数组写入到此文件,并从当前文件指针开始。
(7)void write(byte[] b, int off, int len)
(8)int read()从此文件中读取一个数据字节。
(9)int read(byte[] b)将最多 b.length 个数据字节从此文件读入 byte 数组。
(10)int read( byte[] b, int off, int len)
(11)void writeBytes(String s) 以字节为单位写出字符串,无法写出中文
(12)void writeChars(String s) ,每个字符占两个位置,可以写出中文,使用unicode编码。
(13)void writeUTF(String str)使用utf-8编码方式将一个字符串写出到该文件 ,可以写出中文
(14)void writeBoolean(boolean v)
(15)void writeByte(int v)
(16)void writeChar(int v)
(17)void writeInt(int v)
五、装饰者模式
当需要对已有的对象进行功能增强时,可以定义类(装饰类),将已有的对象传入,基于已有的功能,并提供加强功能,那么自定义的类成为装饰类
1、装饰者设计模式的特点:
装饰对象和真实对象有相同的接口或抽象类
装饰对象包含一个真实对象的引用
装饰对象接收所有的来自客户端的请求,它把这些请求转发给真实的对象
装饰对象可以在转发这些请求之前或之后增加一些附加的功能
2、装饰者设计模式的结构:
(1) 抽象构建角色(Component):
给出一个抽象的接口,以规范准备接受附加责任的对象。相当于IO流里面的InputStream/OutputStream。
(2) 具体的构建角色(ConcreteComponent):
定义一个将要接受附加责任的类。相当于IO里面的FileInputStream/FileOutputStream。
(3).抽象装饰角色(Decorator)
持有一个抽象构建(也就是Component)的引用,并实现这个抽象构建接口。相当于FilterInputStream/FilterOutputStream
(4)具体的装饰角色(ConcreteDecorator)
负责给构建对象“贴上”附加的责任。相当于BufferedInputStream/BufferedOutputStream。
package decorator;
/*
* 抽象构建角色
* */
public interface Love {
public void love();
}
package decorator;
/*
* 具体构建角色
* */
public class Student implements Love{
@Override
public void love() {
System.out.println("学生正在谈恋爱...");
}
}
package decorator;
/*
* 抽象装饰角色
* */
public abstract class Decorator implements Love{
private Love love; // 持有抽象构建角色的引用
public Decorator(Love love){
this.love=love;
}
@Override
public void love() {
this.love.love();
}
}
package decorator;
/*
* 具体装饰角色
* */
public class ConcreteDecorator extends Decorator{
public ConcreteDecorator(Love love){
super(love);
}
public void beautifulLove(){
System.out.println("送花...");
super.love();
System.out.println("结婚...");
}
}
package decorator;
public class Test {
public static void main(String[] args) {
Love love=new Student();
ConcreteDecorator dec=new ConcreteDecorator(love);
dec.beautifulLove();
}
}
补充:
1、装饰者模式和继承的区别:
相同点
装饰模式与继承关系的目的都是要扩展对象的功能
不同点
代码结构比继承更加简洁
装饰模式可以提供比继承更多的灵活性(意味着可以向装饰器的构造方法传入被装饰类的子类对象)
2、组合与继承应用场景
继承是类与类或者接口与接口之间最常见的关系;继承是一种is-a关系
组合(Composition)体现的是整体与部分、拥有的关系,即has-a的关系