一.内存流
内存流主要用来操作内存
BytearrayInputStream和ByteArrayOutputStream输入和输出可以把文件作为数据源,也可以把内存作为数据源
(1)ByteArrayInputStream主要完成将内容从内存读入到程序中,而ByteArrayOutputStream的主要功能是是将数据写入到内存中
(2)注意:因为这两个流没有使用系统资源,所以不用关闭,也不需要抛出异常
内存操作示意图
(1)从程序中读:程序<—ByteArrayInputStream<—内存数据
(2)向内存中写:程序—>ByteArrayOutputStream<—内存数据
ByteArrayOutputStream获取数据的方式
(1)public byte[] toByteAarray():创建一个新分配的字节数组,它的大小 是这个输出流的当前大小和缓冲区的有效内容的副本
(2)public Stirng toString():使用该平台默认的字符集将缓冲区的内容的转换为字符串
例1(利用内存流复制图片):
package bytestream;
import java.io.*;
public class ByteOutputStreamDemo {
public static void main(String[] args) {
File srcFile = new File("d:" + File.separator + "1TX761XVUM10.jpg");// 源文件地址
File destFile = new File("e:" + File.separator + srcFile.getName());// 目标文件地址
InputStream input = null;// 输入流
OutputStream out = null;// 输出流
ByteArrayOutputStream bos = new ByteArrayOutputStream();// 内存流
try {
input = new FileInputStream(srcFile);// 对象用于读取源文件
out = new FileOutputStream(destFile);// 对象用于写入目标文件
byte[] b = new byte[1024];
int len = 0;
// 边读编写
System.out.println("开始复制文件!");
while ((len = input.read(b)) != -1) {
bos.write(b, 0, len);
}
byte[] date = bos.toByteArray();// 创建一个新的字节数组,他的大小是这个输出流的当前大小,和缓冲区的有效 内容的副本
out.write(date);// 讲缓冲区中的内容一次性写入到目标文件中
System.out.println("文件复制完毕......");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 关闭资源
out.close();
input.close();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
运行结果:开始复制文件!
文件复制完毕.....
例2(以byteArrayInputStream为例):
package bytestream;
import java.io.*;
public class ByteArrayInputStreamDemo {
public static void main(String[] args) {
String date="世界,你好!!!!";
/**
* 内存输入流中传入的参数为要读取的字节数组,故将date
* 转化为字节数组date.getBytes(),再传入内存流中
*/
ByteArrayInputStream bis = new ByteArrayInputStream(date.getBytes());
byte[] b=new byte[1024];//自定义缓存区
int len=0;
try {
len=bis.read(b);
System.out.println("读取到的内容是:"+new String(b,0,len));
} catch (IOException e) {
e.printStackTrace();
}
//数据存于缓存区中,缓存流不用关闭
}
}
运行结果:读取到的内容是:世界,你好!!!!
二.打印流
打印流提供了打印方法,可以将各种数据类型原样打印,可以操作输出流和文件
PrintStream:
(1)提供操作字节功能
(2)如果包装的是缓冲流可自动设置flush
(3)可设置字符集
PrintWriter:
(1)没有操作字节功能
(2)内部有缓冲区,即使自动刷新设置为true
(3)可设置字符集
打印流的构造方法
<1>PrintStream的构造方法
(1)public PrintStream(File file)
(2)public PrintStream(OutputStream out)
<2>PrintWriter的构造方法
(1)public PrintWriter(File file)
(2)Public PrintWriter(Writer out)
(3)Public PrintWriter(OutputStream out)
例1(写入一首诗到C盘文件下):
package print;
import java.io.*;
public class PrintStreamDemo {
public static void main(String[] args) {
File f=new File("C:"+File.separator+"静夜诗.txt");
PrintStream ps=null;
try {
ps=new PrintStream(f);
ps.println("\t床前明月光");
ps.println("\t疑是地上霜");
ps.println("\t举头望明月");
ps.println("\t低头思故乡");
ps.println("\t\t\t作者:李白");
System.out.println("打印成功...");
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally{
ps.close();
}
}
}
运行结果:打印成功...
例2(PrintStream若包装缓冲流可设置flush):
package print;
import java.io.*;
public class PrintStreamDemo2 {
public static void main(String[] args) {
File f=new File("c:"+File.separator+"兵法.txt");
PrintStream ps=null;
OutputStream out=null;
try {
out=new FileOutputStream(f);
BufferedOutputStream bos= new BufferedOutputStream(out);
ps=new PrintStream(bos);
ps.println("战武七经:");
ps.println("1.孙子兵法");
ps.println("2.六韬.三略");
ps.println("3.吴子");
ps.println("4.司马法");
ps.println("5.孙膑兵法");
ps.flush();//将缓冲流中的数据刷入文件中
System.out.println("打印成功....");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
运行结果:打印成功....
三.对象流,序列化与反序列化
相关类
(1)ObjectOutputStream(用于序列化)
(2)ObjectInputStream(用户反序列化)
2.适用对象流可以实现对象不得序列化与反序列化操作
3.为什么要序列化
(1)易于保存
(2)易于保存
4.序列化与反序列化的过程
(1)序列化:Java对象——>对象的二进制形式
(2)反序列化:Java对象<——对象的二进制形式
*这种方式被称为序列化与反序列化
<1>序列化是将对象的状态存储到特定的存储介质中的过程(将对象转化成特定的字节序列(二进制)的过程)
<2>反序列化则是从特定的存储介质中的数据重新构建对象的过程(将对象的二进制形式转化成对象)
5.序列化的步骤
(1)实现Serializble接口
(2)创建对象输出流
(3)调用writeObject(Object obj)方法将对象写入输出流中
(4)关闭对象输出流
6.反序列化步骤
(1)实现Serializble接口
(2)创建对象输入流
(3)调用readObject()方法读取对象
(4)关闭对象输入流
@@创建Person用于举例:
package serializable;
import java.io.Serializable;
public class Person implements Serializable {
/**
* 对象类,用于序列化
*/
private static final long serialVersionUID = 1L;
private String name;
private int age;
private double score;
public Person() {
super();
}
public Person(String name, int age, double score) {
super();
this.name = name;
this.age = age;
this.score = score;
}
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 double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", score=" + score
+ "]";
}
}
例1(序列化普及对象)
package serializable;
import java.io.*;
public class SerialPerson {
public static void main(String[] args) {
File f=new File("d:"+File.separator+"Serbial.txt");
ObjectOutputStream oos=null;
OutputStream out=null;
Person per=new Person("Jack",21,98.7);
try {
System.out.println("开始序列化");
out=new FileOutputStream(f);
oos=new ObjectOutputStream(out);
oos.writeObject(per);
System.out.println("系列化 成功......");
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
out.close();
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
运行结果:开始序列化
系列化 成功......
例2(普通反序列化)
package serializable;
import java.io.*;
public class DeSerialPerson {
public static void main(String[] args) {
File f = new File("d:" + File.separator + "Serbial.txt");
InputStream input = null;
ObjectInputStream ois = null;
try {
System.out.println("开始反序列化!!!");
input = new FileInputStream(f);
ois = new ObjectInputStream(input);
Person per=(Person)ois.readObject();
System.out.println("反序列化成功。。。。。");
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
ois.close();
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
运行结果:开始反序列化!!!
Person [name=Jack, age=21, score=98.7]
例3(序列化集合)
package serializable;
import java.io.*;
import java.util.*;
public class SerialListDemo {
public static void main(String[] args) {
File f=new File("d:"+File.separator+"listSer.txt");
List
(); Collections.addAll(list, new Person("郭靖",21,96.2),new Person("黄蓉",22,93.2),new Person("小龙女",19,94.6),
new Person("杨过",15,95.3));
OutputStream out=null;
ObjectOutputStream oos=null;
try {
System.out.println("开始序列化");
out=new FileOutputStream(f);
oos=new ObjectOutputStream(out);
oos.writeObject(list);
System.out.println("系列化成功.......");
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
out.close();
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
运行结果为:
开始序列化
系列化成功.......
例4(反序列化集合)
package serializable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.util.List;
public class DeSerialList {
public static void main(String[] args){
File f=new File("d:"+File.separator+"listSer.txt");
InputStream input=null;
ObjectInputStream ois=null;
try {
System.out.println("开始反序列化");
input=new FileInputStream(f);//输入流
ois=new ObjectInputStream(input);//封装输入流到对象流中
List
) ois.readObject();//向上 转型for(Person per:list){
System.out.println( per);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
input.close();
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
运行结果:
开始反序列化
Person [name=郭靖, age=21, score=96.2]
Person [name=黄蓉, age=22, score=93.2]
Person [name=小龙女, age=19, score=94.6]
Person [name=杨过, age=15, score=95.3]
四.RandomAccessFile
1.直接继承Object
2.主要功能是完成随机读写功能,可以读取指定位置的内容
3.构造方法:
(1)public RandomAccessFile(File file,String mode)(2)public RanaccessFile(String name,String mode)
(3)只能操作文件
4.文件的打开模式(mode)
(1)”r”以只读方式打开,调用结果对象的任何write方法都将抛出异常IOException
(2)“rw”打开以便于读取和写入,如果该文件上不存在,则尝试创建该文件
5.RandomAccessFile的常用方法
(1)void seek(long pos)设置文件指定偏移量, 在该位置准备开始读写
(2)Int sikpByte(int n)尝试跳过输入的n个字节,返回实际跳过的字节数
(3)Long getFilePointer()获取此文件中的 当前偏移量
(4)Long length()返回此文件的长度
(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 witreBoolean(boolean v)
(15)Void writeByte(int v)
(16)Void writeChar(int v)
(17)Void writeInt(int v)
例1.(以RandomAccessFile基本方法为例)
package raf;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileDemo {
public static void main(String[] args) {
File f=new File("d:"+File.separator+"Ran.txt");
RandomAccessFile raf=null;
try {
raf=new RandomAccessFile(f,"rw");
raf.writeBoolean( true);
raf.writeChar('A');
raf.writeChars("hello");
raf.writeChars("中华人名共和国");
System.out.println("写入成功.....");
raf.seek(9);
System.out.println("文件当前位置指针:"+raf.getFilePointer());
System.out.println("当前位置字符:"+raf.readChar());
raf.seek(3);
System.out.println("文件当前位置指针:"+raf.getFilePointer());
System.out.println("当前位置字符:"+raf.readChar());
raf.seek(10);
System.out.println("文件当前位置 指针"+raf.getFilePointer());
System.out.println("文件当前位置在字符:"+raf.readChar());
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
运行结果:
写入成功.....
文件当前位置指针:9
当前位置字符:l
文件当前位置指针:3
当前位置字符:h
文件当前位置 指针10
文件当前位置在字符:氀
例2(RandomAccessaFile注意点)
package raf;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RafString {
public static void main(String[] args) {
File f=new File("d:"+File.separator+"raf.txt");
RandomAccessFile raf=null;
try {
raf=new RandomAccessFile(f,"rw");
raf.writeBytes("×××");//会丢弃高八位的方式写入字符串中的每个字符
raf. writeChars("中央 人民政府");//会将字符串中的每个字符写入
raf.seek(3);//设置文件指针
System.out.println("当前 指针位置的字符为:"+raf.readChar());
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
运行结果为:
当前 指针位置的字符为:?
五.装饰者模式
当需要对已有的对象进行功能增强时,可以定义类(装饰类),将已有的对象的话传入,基于已有的功能,并提供增强功能,那么自定义的类称为装饰 类
相同点:装饰者模式与继承关系的目的都是要扩展对象的功能
不同点:
(1)代码的结构比继承更加简洁
(2)装饰者模式可以提供比继承更多的灵活性(意味着可以向装饰器的构造方法传入被装饰类的子类对象)
装饰者设计模式的特点
(1)装饰对象和真实对象有相同的接口或抽象类
(2)装饰对象包含一个真实对象的引用
(3)装饰对象接收所有来自客户端的请求,他把这些请求转发给真实对象
(4)装饰对像可以在转发这些请求之前或之后增加一些附加的功能
装饰者设计模式的结构
(1)抽象构建角色:给出一个抽象接口,以规范准备接受附加责任的对象,相当于IO流中的InputStream/OutputStream
(2)具体构建角色:定义一个将要接受附加责任的类,相当于IO流中的FileInputStream/FileOutputStream
(3)抽象装饰角色:持有一个抽象构建角色(也就是Component)的引用,并实现这个与抽象构建接口,相当于FileterInputStream/FileterOutputStream
(4)具体的装饰角色:负责给构建对象“贴上”附加的责任。相当于BufferedInputStream/BufferedOutputStream
例.(装饰一个学生的学习方法)
*抽象构建接口
package decorator;
/**
* 抽象构建接口
* @author Qitao
*/
public interface Study {
public void study();
}
*具体构建角色
package decorator;
/**
* 具体构建角色
* @author Administrator
*/
public class Student implements Study{
@Override
public void study() {
System.out.println("学生正在学习...");
}
}
*抽象装饰角色
package decorator;
/**
* 抽象装饰角色
* @author Administrator
*/
public abstract class Decorator implements Study{
private Study study;
public Decorator(Study study) {
super();
this.study = study;
}
@Override
public void study() {
this.study.study();
}
}
*具体装饰角色
package decorator;
/**
* 具体装饰角色
* @author Administrator
*/
public class ConcreteDecorator extends Decorator{
public ConcreteDecorator(Study study) {
super(study);
}
public void goodStudy(){
System.out.println("课前预习...");
super.study();
System.out.println("课后复习...");
}
}
*测试装饰者设计模式类:
package decorator;
/**
* 测试装饰者设计模式
* @author Administrator
*/
public class Test {
public static void main(String[] args){
Study study=new Student();
ConcreteDecorator con=new ConcreteDecorator(study);
con.goodStudy();
}
}
运行结果:
课前预习...
学生正在学习...
课后复习...