缓冲流
作用:主要是为了增强基础流的功能而存在的,提高了流的工作效率【读写效率】
注意:如果使用记事本创建的文件,文件是utf-8或者unicode编码,文件的前面有一个BOM(Byte Order Mark)头,BOM作用指定文件使用的编码类型。GBK编码没有添加bom头。
utf-8:EF BB BF
unicode 小端: FF FE 66 00
unicode 大端 :FE FF 00 66
1.1 BufferedInputStream类
public class BufferedInputStreamDemo {
public static void main(String[] args) throws IOException {
//实例化一个File对象
File file = new File("file/test22.txt");
//实例化一个缓冲字节输入流的对象
BufferedInputStream input = new BufferedInputStream(new FileInputStream(file));
/*
//读取
byte[] arr = new byte[1024];
int len = 0;
while((len = input.read(arr)) != -1) {
String string = new String(arr, 0, len);
}
*/
byte[] arr = new byte[4];
int len = input.read(arr);
String string = new String(arr, 0, len);
System.out.println(string);
input.mark(66);
len = input.read(arr);
string = new String(arr, 0, len);
System.out.println(string);
// 实现了效果:覆水可收
input.reset();
len = input.read(arr);
string = new String(arr, 0, len);
System.out.println(string);
input.close();
}
}
1.2 BufferedOutputStream类
public class BufferedOutputStreamDemo {
public static void main(String[] args) throws IOException {
//实例化FIle对象
File file = new File("test33.txt");
//实例化换种字节输出流
BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(file));
//写
output.write("你好的halle".getBytes());
//刷新
output.flush();
//关闭
output.close();
}
}
1.3 BufferedReader类
public class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
//实例化FIle对象
File file = new File("test33.txt");
//实例化缓冲字符流的对象
BufferedReader reader = new BufferedReader(new FileReader(file));
//方式一:read循环读取
/*
//读取
char[] arr = new char[8];
int len = 0;
while((len = reader.read(arr)) != -1) {
String string = new String(arr, 0, len);
}
*/
//方式二:readLine循环读取
/*
String result1 = reader.readLine();
System.out.println(result1);
String result2 = reader.readLine();
System.out.println(result2);
*/
String result = "";
while((result = reader.readLine()) != null) {
System.out.println("第一行:" + result);
}
reader.close();
}
}
1.4 BufferedWriter类
public class BufferedWriterDemo {
public static void main(String[] args) throws IOException {
// 实例化FIle对象
File file = new File("test33.txt");
//实例化缓冲字符输出流
BufferedWriter writer = new BufferedWriter(new FileWriter(file,true));
// 写
writer.write("今天天气还可以");
// 作用:主要就是为了换行
writer.newLine();
// 刷新
writer.flush();
//关闭
writer.close();
}
}
第二节 内存流
输入和输出都是从文件中来的,当然,也可将输出输入的位置设置在内存上,这就需要ByteArrayInputStream和ByteArrayOutputStream
ByteArrayInputStream:将内容写入到内存中,是Inputstream的子类
ByteArrayOutputStream:将内存中数据输出,是OutputStream的子类
此时的操作应该以内存为操作点
案例:完成一个字母大小写转换的程序
public class TextDemo02 {
public static void main(String[] args) throws IOException {
//定义一个字符串,全部由大写字母组成
String string = "HELLOWORLD";
//内存输入流
//向内存中输出内容,注意:跟文件读取不一样,不设置文件路径
ByteArrayInputStream bis = new ByteArrayInputStream(string.getBytes());
//内存输出流
//准备从内存中读取内容,注意:跟文件读取不一样,不设置文件路径
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int temp = 0;
//read()方法每次只读取一个字符
while((temp = bis.read()) != -1) {
//将读取的数字转为字符
char c = (char)temp;
//将字符变为大写
bos.write(Character.toLowerCase(c));
}
//循环结束之后,所有的数据都在ByteArrayOutputStream中
//取出内容,将缓冲区内容转换为字符串
String newString = bos.toString();
//关闭流
bis.close();
bos.close();
System.out.println(newString);
}
}
实际上以上操作很好体现了对象的多态。通过实例化其子类不同,完成的功能也不同,也就相当于输出的位置不同,如果是输出文件,则使用FileXxxx类。如果是内存,则使用ByteArrayXxx。
总结:
a.内存操作流的操作对象,一定是以内存为主准,不要以硬盘为准。
b.实际上此时可以通过向上转型的关系,为OutputStream或InputStream.
c.内存输出流在日后的开发中也是经常使用到,所以一定要重点掌握
第三节 标准输入输出流
Java的标准输入/输出分别通过System.in和System.out实现,默认情况下分别代表是键盘和显示器
public class PrintStreamDemo {
public static void main(String[] args) throws FileNotFoundException {
//System.out.println("hello world");
//创建打印流的对象
//注意:默认打印到控制台,但是,如果采用setOut方法进行重定向之后,将输出到指定的文件中
PrintStream print = new PrintStream(new FileOutputStream(new File("test33.txt")));
/*
* static void setErr(PrintStream err)
重新分配“标准”错误输出流。
static void setIn(InputStream in)
重新分配“标准”输入流。
static void setOut(PrintStream out)
重新分配“标准”输出流。
* */
//将标准输出重定向到print的输出流
System.setOut(print);
System.out.println("hello world");
}
}
public class InputStreamDemo {
public static void main(String[] args) throws FileNotFoundException {
FileInputStream inputStream = new FileInputStream(new File("test33.txt"));
//setIn
System.setIn(inputStream);
//System.out.println("请输入内容:");
//默认情况下是从控制台进行获取内容
//但是如果使用setIn方法设置了重定向之后,将从指定文件中获取内容
Scanner sc = new Scanner(System.in);
String string = sc.next();
System.out.println(string);
}
}
第四节 对象流
流中流动的数据是对象
将一个对象写入到本地文件中,被称为对象的序列化
将一个本地文本中的对象读取出来,被称为对象的反序列化
使用对象流
ObjectInputStream: 对象输出流
ObjectOutputStream:对象输入流
注意:
一个对象流只能操作一个对象,如果试图采用一个对象流操作多个对象的话,会出现EOFException【文件意外达到了文件末尾】
如果向将多个对象序列化到本地,可以借助于集合,【思路:将多个对象添加到集合中,将集合的对象写入到本地文件中,再次读出来,获取到的仍然是集合对象,遍历集合】
对象中那些字段可以不序列化:
1 transient 修饰的字段
2 静态的字段
在要序列化类中添加字段,保证序列化和反序列化是同一个类
private static final long serialVersionUID = 100L;
public class ObjectStreamDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
//objectOutputStreamUsage();
objectInputStreamUsage();
}
// 写:将对象进行序列化
public static void objectOutputStreamUsage() {
//1.实例化一个Person的对象
Person person = new Person("张三", 10, 'B');
//2.实例化一个对象输出流的对象
ObjectOutputStream output = null;
try {
output = new ObjectOutputStream(new FileOutputStream(new File("file/person.txt")));
//3.将对象写入到流中
output.writeObject(person);
//4.刷新
output.flush();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
try {
output.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// 读:反序列化
public static void objectInputStreamUsage() {
//1.实例化对象输入流的对象
try {
ObjectInputStream input = new ObjectInputStream(new FileInputStream(new File("file/person.txt")));
//2.读取
Object object = input.readObject();
//3.对象的向下转型
if(object instanceof Person) {
Person p = (Person)object;
System.out.println(p);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
注意:在使用对象流的时候,用于初始化对象流的参数只能是字节流(将对象转换为二进制的形式,然后再把二进制写入文件)
第五节 RandomAccessFile类
RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了。这些记录的大小不必相同;但是其大小和位置必须是可知的。但是该类仅限于操作文件。
案例一:RandomAccessFile类的应用
public class TextDemo01 {
public static void main(String[] args) throws Exception {
RandomAccessFile file = new RandomAccessFile("file.txt", "rw");
// 以下向file文件中写数据
file.writeInt(20);// 占4个字节
file.writeDouble(8.236598);// 占8个字节
//这个长度写在当前文件指针的前两个字节处,可用readShort()读取
file.writeUTF("这是一个UTF字符串");
file.writeBoolean(true);// 占1个字节
file.writeShort(395);// 占2个字节
file.writeLong(2325451l);// 占8个字节
file.writeUTF("又是一个UTF字符串");
file.writeFloat(35.5f);// 占4个字节
file.writeChar('a');// 占2个字节
//把文件指针位置设置到文件起始处
file.seek(0);
// 以下从file文件中读数据,要注意文件指针的位置
System.out.println("——————从file文件指定位置读数据——————");
System.out.println(file.readInt());
System.out.println(file.readDouble());
System.out.println(file.readUTF());
//将文件指针跳过3个字节,本例中即跳过了一个boolean值和short值。
file.skipBytes(3);
System.out.println(file.readLong());
//跳过文件中“又是一个UTF字符串”所占字节
//注意readShort()方法会移动文件指针,所以不用写2。
file.skipBytes(file.readShort());
System.out.println(file.readFloat());
// 以下演示文件复制操作
System.out.println("——————文件复制(从file到fileCopy)——————");
file.seek(0);
RandomAccessFile fileCopy = new RandomAccessFile("fileCopy.txt", "rw");
int len = (int) file.length();// 取得文件长度(字节数)
byte[] b = new byte[len];
//全部读取
file.readFully(b);
fileCopy.write(b);
System.out.println("复制完成!");
}
}
第六节 Properties类
是Map接口的一个实现类,并且是Hashtable的子类
Properties文件中元素也是以键值对的形式存在的
Properties特点:
1 存储属性名和属性值
2 属性名和属性值都是字符串
3 和流有关系
4 没有泛型
public class PropertiesDemo {
public static void main(String[] args) {
//1.实例化一个Properties的对象
Properties pro = new Properties();
System.out.println(pro);
//2.把文件userlist.properties中的键值对同步到集合中
//实质:读取
/**
* void load(InputStream inStream)
从输入流中读取属性列表(键和元素对)。
*/
try {
pro.load(new BufferedInputStream(new FileInputStream(new File("file/userlist.properties"))));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(pro);
//3.向集合中添加一对键值对
/*
* Object setProperty(String key, String value)
调用 Hashtable 的方法 put。
* */
pro.setProperty("address", "china");
System.out.println(pro);
try {
//4.store
//实质:写入
//comments:工作日志
pro.store(new BufferedOutputStream(new FileOutputStream(new File("file/userlist.properties"))), "add a pair of key and value");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
第七节 装饰者设计模式
装饰者模式是向一个现有的对象添加新的功能,同时又不改变其结构。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
应用场景:需要扩展、增强一个类的功能,或给一个类添加附加职责。
扩展类的功能有两种实现方法:
1 继承重写
优点:简单
缺点:1 类体系太庞大 2 耦合性太高 3子类继承不需要的方法
2 装饰者模式
缺点:多层装饰比较复杂
优点:耦合性低,提高重用性,符合合成(聚合)复用原则
java面向对象的设计原则 7大原则
开(总则) 开闭原则, 对扩展开放,对修改关闭
口 :接口隔离原则,使用接口隔离,降低程序耦合性
合 :合成聚合复用,不用继承,使用组合(强拥有关联)、聚合(弱拥有关联) 学校类 (List)
里 : 里氏替换原则,多态 父类能使用的地方,都可以替换成子类 Animal animal=new Dog();
最 :最少知道原则(迪米特法则),一个类不要知道太多其他的类
单: 单一职责原则,一个类只负责一类功能,如果一个类功能太多,需要拆分。
依: 依赖倒置原则,不依赖具体的类,依赖接口或抽象类。降低程序耦合性
代码实现:
/**
* 抽象人类
* @author wgy
*
*/
public abstract class AbstractPerson {
public abstract void eat();
}
/**
*子类1
*/
public class Student extends AbstractPerson {
String name;
String school;
public void eat() {
System.out.println(name+"正在吃东西.........");
}
}
package com.qf.day18_6;
/**
* 子类2
* @author wgy
*
*/
public class Teacher extends AbstractPerson{
String name;
int workyear;
@Override
public void eat() {
System.out.println(name+"吃......");
}
}
package com.qf.day18_6;
import java.io.BufferedInputStream;
/**
* 增强Person
* @author wgy
*
*/
public class StrongPerson extends AbstractPerson {
//使用person创建一个变量
AbstractPerson p;
public StrongPerson(AbstractPerson p) {
this.p = p;
}
public void eat() {
p.eat();
System.out.println("抽一口");
System.out.println("眯一会");
System.out.println("写会java代码");
}
}
//测试类
package com.qf.day18_6;
public class Test {
public static void main(String[] args) {
Student benwei=new Student();
benwei.name="本伟";
Teacher zhengshuai=new Teacher();
zhengshuai.name="郑帅";
StrongPerson strongPerson=new StrongPerson(benwei);
StrongPerson strongPerson2=new StrongPerson(zhengshuai);
strongPerson.eat();
strongPerson2.eat();
}
}
扩展案例:
1 抽象类 ReadFile -->read抽象方法
2 定义一些子类
ReadTextFile 读取文本文件
ReadMusicFile 读取音乐文件
ReadVideoFile 读取视频文件
3 要求:提高三个类的功能 带缓冲
3.1继承
BufferedReadTextFile继承ReadTextFile 重写 read方法
BufferedReadMusicFile继承ReadMusicFile 重写 read
BufferedReadVideoFile继承ReadVideoFile 重写 read
缺点:1 类体系太庞大 2 耦合性太高
3.2装饰者设计模式 :采用组合的关系
BufferedReadFile{
private ReadFile readFile;
public BufferedReadFile(ReadFile readFile){
this.readFile=readFile;
}
public void read(){
///
}
}