Java 之 Java 缓冲流与序列化

缓冲流

缓冲流(高效率的流)
BufferedOutputStream 缓冲输出字节流
构造方法:
BufferedOutputStream(OutputStream out)
参数:字节输出流的父类 FileOutputStream
使传进来的流更高效

BufferedInputStream 缓冲输入字节流

这里写图片描述

字节流与缓冲流的区别

当程序发出指令去读取一个文件时,对比使用字节流和缓冲流的区别:
字节流:程序——JVM——磁盘文件——JVM——程序,同理写入到其他文件中去(但每次只读一个字节)
缓冲流:与字节流不同的是JVM会开辟一个缓冲区,将每次读取的字节先存到缓冲区中,
当缓冲区存满时再将缓冲区中的内容写入到其他文件中,当缓冲区没有存满时,不会写入。

假设一个文件有1024个字节,缓冲区大小为100个字节,那么要读取11次,最后一次只有24个字节,
但此时缓冲区并没有存满,不能将存储的内容从缓冲区中取出。
这时我们可以调用缓冲流自带的一个方法flush(强制写入)将最后一次读取的内容强制写入到文件中去。

字节流与字符流的效率对比
当读取一个较小的文件时,字节流与缓冲流效率差别不大
但当我们读取一个较大的文件时,通过实际测试对比发现缓冲流明显比字节流快得多。

BufferedInputStream比FileInputStream多了一个缓冲区,执行read时先从缓冲区读取,
当缓冲区数据读完时再把缓冲区填满。
因此,当每次读取的数据量很小时,FileInputStream每次都是从硬盘读入,
而BufferedInputStream大部分是从缓冲区读入。读取内存速度比读取硬盘速度快得多,
因此BufferedInputStream效率高。
BufferedOutputStream和FileOutputStream同理,差异更明显一些。
使用缓冲流 BufferedOutputStream 写入文件
FileOutputStream fos = new FileOutputStream("/Users/Desktop/Test/Test.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write("HelloWorld".getBytes());
bos.close();
使用缓冲流 BufferedIntputStream 读取文件
FileInputStream fis = new FileInputStream("/Users/Desktop/Test/Test.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
byte[] b = new byte[1024];
int len = 0;
while((len = bis.read(b)) != -1){
	System.out.println(new String(b, 0, len));
}
bis.close();
测试,比较使用缓冲流复制文件和不使用缓冲流复制文件所用时间差距
public class Test{
	public static void main(String[] args) throws IOException {
		// 测试
		new fun1.printTime();
		new fun2.printTime();
		new fun3.printTime();
		new fun4.printTime();
	}
}
// 程序的开始部分和结尾部分均相同,创建抽象类
abstract class TestTime {
	// 源文件路径
	public String src = "/Users/DeskTop/Test/Test.png";
	// 目的文件路径
	public String dest = "/Users/DeskTop/Test/Tests.png";
	// 统计花费时间方法
	public void printTime() throws IOException {
		// 获取程序开始时间
		long start  = System.currentTimeMillis();
		// 调用抽象方法复制文件
		copyFile();
		// 获取程序结束时间
		long end = System.currentTimeMillis();
	}
	// 抽象方法,字符流/缓冲流复制文件
	public abstract void copyFile() throws IOException;
	// 抽象方法,打印两种方法所用时间
	public abstract void printSpeedTimes(long start, long end);
}
// 字符流复制文件
abstract class Mycopy1 extends TestTime {
	public void copyFile() throws IOException {
		FileInputStream fis = new FileInputStream(src);
		FileOutputStream fos = new FileOutputStream(dest);
		int len = 0;
		// 调用内部实现的抽象方法
		run1(len, fis, fos);
		fis.close();
		fos.close();
	}
	// 内部实现的抽象方法
	public abstract void run1(int len, FileInputStream fis, FileOutputStream fos) throws IOException);
	public abstract void printSpeedTimes(long start, long end);
}
// 字节流单字节内部实现
class fun1 extends Mycopy1 {
	public void run1(int len, FileInputStream fis, FileOutputStream fos) throws IOException {
		while((len = fis.read()) != -1){
			fos.write((char)len);
		}
	}
	// 花费时间
	public void printSpeedTimes(long statr, long end){
		System.out.println("字节流单字节复制耗费时间:" + (end - start));
	}	
}
// 字节流数组
class fun2 extends Mycopy1 {
	public void run1(int len, FileInputStream fis, FileOutputStream fos) throws IOException {
		byte[] b = new byte[1024];
		while ((len = fis.read(b)) != -1) {
			fos.write(b, 0, len);
		}
	}
	public void printSpeedTimes(long start, long end) {
		System.out.println("字节流数组复制耗费时间:" + (end - start));
	}
}
// 使用缓冲流单字节复制文件
abstract class Mycopy2 extends TestTime {
	public void copyFile() throws IOException {
		FileInputStream fis = new FileInputStream(src);
		FileOutputStream fos = new FileOutputStream(dest);
		BufferedInputStream bis = new BufferedInputStream(fis);
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		int len = 0;
		run2(bis, bos, len);
		bis.close();
		bos.close();
	}
	public abstract void printSpeedTimes(long start, long end) ;
	public abstract void run2(BufferedInputStream bis, BufferedOutputStream bos, int len) throws IOException;
}
class fun3 extends Mycopy2 {
	public void run2(BufferedInputStream bis, BufferedOutputStream bos, int len) throws IOException {
		while ((len = bis.read()) != -1) {
			bos.write(len);
		}
	}
	public void printSpeedTimes(long start, long end) {
		System.out.println("缓冲流字节复制耗费时间:" + (end - start));
	}
}
class fun4 extends Mycopy2{
	@Override
	public void printSpeedTimes(long start, long end) {
		System.out.println("缓冲流数组复制耗费时间:" + (end - start));
	}
	public void run2(BufferedInputStream bis, BufferedOutputStream bos, int len) throws IOException {
		byte[] b = new byte[1024];
		while ((len = bis.read(b)) != -1) {
			System.out.println(new String(b, 0, len));
		}
	}
}

缓冲字符流

缓冲字符流
BufferedWriter
构造方法:
参数: Writer(父类)
可传 FileWriter OutputStreamWriter
特有方法
newLine() 此方法无关平台性 
mac 为 \n
Windows 为 /r/n

BUfferedReader
使用 BufferedWriter 写入文件
FileWriter fw = new FileWriter("/Users/Desktop/Test/Test.txt");
BufferedWriter bw = new BufferedWriter(fw);
bw.write("雪中智代雨中杏,");
bw.newLine();
bw.flush();
bw.write("樱下小渚花田汐。");
bw.newLine();
bw.flush();
bw.write("香醇宫泽黑琴美,");
bw.newLine();
bw.flush();
bw.write("天际芽衣黄昏椋。");
bw.newLine();
bw.flush();
bw.close();
使用 BufferedReader 读取文件
FileReader fr = new FileReader("/Users/Desktop/Test/Test.txt");
BufferedReader br = new BufferedReader(fr);
// 按行来读
// 在读取时,BufferedReader 不能把换行也一起读出来
// 所以,在读取时,要与原文本一样,就需要加上换行符来打印
String string = "";
while((string = br.readLine()) != null) {
	System.out.println(string);
}
br.close();
使用缓冲流进行文件复制
// 读
FileReader fr = new FileReader("/Users/Desktop/Test/Test.txt");
BufferedReader bf = new BufferedReader(fr);
// 写
FileWriter fw = new FileWriter("/Users/Desktop/Test/Tests.txt");
BufferedWriter bw = new BufferedWriter(fw);
// 边读边写
String string = "";
while((string = bf.readLine()) != null){
	bw.write(string);
	bw.newLine();
	bw.flush();
}
bf.close();
bw.close();

流总结

1.明确要做的操作
读取数据源
InputStream
Reader
写到数据目的地
OutputStream
Writer
2.明确要操作的是什么内容
文本、音频、图片、视频---使用字节流(全能流)
文本(按编码格式读写) ---使用字符流
3.明确流要在什么设备上使用
文本
网络通过流进行数据交互---字节流
4.是否需要提高效率
Buffered 缓冲流
应用场景:迅雷加速器会员非会员

Properties

Properties 集合(双列集合)父类 Hashtable
作用:Properties 是集合中唯一一个能和 IO 流配合的集合类

读取和写入是参数
可以是字符流
也可以是字节流(必须要使用转换流)
// 写入
Properties properties = new Properties();
properties.put("name", 1);
// 注意:该集合最好使用的是 key 和 value 都是字符串
// 最好都使用该集合
properties.setProperty("gender", "女");
System.out.println(properties);
// 遍历集合
// 取出所有 key 的集合
Set<String> set =  properties.stringPropertyNames();
for(String key : set) {
	// 获取 value
	String value = properties.getProperty(key);
	System.out.println(key + ":" + value);
}
// 读取
Properties properties = new Properties();
FileReader fr = new FileReader("/Users/Desktop/Test/Test.txt");
properties.load(fr);
System.out.println(properties);
fr.close();
Properties properties = new Properties();
properties.setProperty("a","啊");
properties.setProperty("b", "吧");
properties.setProperty("c", "从");
// 后缀名是什么,都不会产生影响
// 一般写法,使用. properties 当做文件后缀名,来标识该文件可以使用 properties 类读取
FileWriter fw = new FileWriter("/Users/Desktop/Test/Test.properties");
// 利用 properties 类中的方法写入
// 参数二:相当于写入文件的注释,一般什么都不写
// 在 properties 文件中,可以使用#号来写注释
properties.store(fw, "");
fw.close();

序列化与反序列化

序列化:把对象写进文件中
反序列化:从文件中把对象读出来


对象流
ObjectInputStream
ObjectOutputStream

注意:静态成员变量是不能进行序列化的
序列化:序列是对象,静态成员变量是属于类的

序列化相当于是把对象进行持久化文件

这里写图片描述

// 读取序列化文件(反序列化)
// 在进行反序列化(读取)的时候,需要依赖你的编译文件. class 文件来进行读取
FIleInputStream fis = new FIleInputStream("/Users/Desktop/Test/Test.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
// 读文件
Object object = ois.readObject();
System.out.println(object);
ois.close();
// 注意:如果要对对象进行实例化
//        必须要实现 Serializable (序列化接口)
//        Serializable 该接口是标记型接口
// 写对象都使用字节流去操作
FIleOutputStream fos = new FIleOutputStream("/Users/Desktop/Test/Test.txt");
// 对象输出流(序列化流)
ObjectOutputStream oos = new ObjectOutputStream(fos);
// 使用写对象的方法
oos.writerObject(new Person("dp",15));
ooc.close();
public class Person implements Serializable{
	/**
	 * 序列化使用序列号
	 * 只要写了这个号,在编译时,系统就不会重新计算序列号了
	 */
	private static final long serialVersionUID = 1L;
	// 不想写成静态,也不想序列化,怎么办?
	// 使用 transient 关键字 瞬态关键字
	// 作用:可以组织成员变量序列化
	private transient String name;
	private int age;
	public Person() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = 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;
	}
	@Override
	public String toString() {
		return "[姓名:" + name + "]\n[年龄:" + age + "]";
	}
}
/*
 * 学生类
 * 姓名 性别 年龄 空参有参构造 set和get方法 toString方法
 * 键盘录入6个学员信息(格式为  张三,男,25),要求有两个相同的信息,将6个学员信息存入到ArrayList集合中
 * 将存有6个学员信息的ArrayList集合对象写入到文件中
 * 读取文件中的ArrayList对象
 * 对集合中的6个学生对象进行去重并按照年龄从小到大的顺序排序
 * 再将排序完成的集合写进重新写进文件中
 * 再重新读取,查看排序结果
 * 
 * 注意:一般序列化的对象,只存一个容器
 */
public class Student implements Serializable ,Comparable<Student>{
	private static final long serialVersionUID = 1L;
	private String name;
	private String gender;
	private int age;
	public Student() {
		super();
	}
	public Student(String name, String gender, int age) {
		super();
		this.name = name;
		this.gender = gender;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "[姓名:" + name + ", 性别:" + gender + ", 年龄:" + age + "]";
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((gender == null) ? 0 : gender.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Student other = (Student) obj;
		if (age != other.age)
			return false;
		if (gender == null) {
			if (other.gender != null)
				return false;
		} else if (!gender.equals(other.gender))
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	@Override
	public int compareTo(Student o) {
		int num = this.age - o.getAge();
		return num;
	}
}
public class Demo {
	public static void main(String[] args) throws IOException, ClassNotFoundException {
		ArrayList<Student> studentList = getStudentList();
		writerList(studentList);
		ArrayList<Student> readList = readList();
		for (Student student : readList) {
			System.out.println(student);
		}
		TreeSet<Student> set = new TreeSet<>();
		// 添加到 set 中去重排序
		// 注意:必须要实现 comparable 接口,或者传入比较器
		set.addAll(readList);
		// 重新放入到 list 中
		// 重新写入
		readList.clear();
		readList.addAll(set);
		writerList(readList);
		ArrayList<Student> readList2 = readList();
		for (Student student : readList2) {
			System.out.println(student);
		}
	}
	// 键盘输入学生,并且返回装好学生的数组
	public static ArrayList<Student> getStudentList(){
		ArrayList<Student> list = new ArrayList<>();
		Scanner scanner = new Scanner(System.in);
		while (list.size() < 6) {
			System.out.println("请按格式(姓名,性别,年龄)输入学生:");
			String string = scanner.nextLine();
			try {
				// 切割
				String[] split = string.split(",");
				String name = split[0];
				String gender = split[1];
				int age = Integer.parseInt(split[2]);
				// 创建学生对象
				Student student = new Student(name, gender, age);
				// 装进数组
				list.add(student);				
			}catch (ArrayIndexOutOfBoundsException e) {
				System.out.println("数组越界,请重写!");
			} catch (Exception e) {
				System.out.println("格式有误,请重新输入!");
			}
		}
		scanner.close();
		return list;
	}
	// 把集合直接写入到文件中(序列化)
	private static void writerList(ArrayList<Student> student) throws IOException {
		FileOutputStream fos = new FileOutputStream("/Users/Desktop/Test/student.txt");
		// 对象输出流(序列化流)
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		// 使用写对象的方法
		oos.writeObject(student);
		oos.close();
	}
	@SuppressWarnings("unchecked")
	private static ArrayList<Student> readList() throws IOException, ClassNotFoundException {
		FileInputStream fis = new FileInputStream("/Users/Desktop/Test/student.txt");
		ObjectInputStream ois = new ObjectInputStream(fis);
		// 读文件
		Object object = ois.readObject();
		ArrayList<Student> list = (ArrayList<Student>)object;
		ois.close();
		return list;
	}
}

http://blog.csdn.net/huzongnan/article/list

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值