一阶段:第13天:缓冲流(8.9)
一.转换流
InputStreamReader:字节字符转换输入流,将字节输入流转换为字符输入流
把外部设备中的二进制数据读取到内存转成字符,指定编码,字节流
OutputStreamWriter:字符转换输出流,将内存中的字符转成字节保存到硬盘中。
把内存中的字符使用指定的编码占城二进制数据,保存到外部设备
如果使用记事本创建的文件,文件是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字节转换输入流(InputStreamReader)
// 使用转换流读取文件
public class Demo5 {
public static void main(String[] args) throws Exception{
//创建转换输入流
FileInputStream fis=new FileInputStream("e:\\cc.txt");
//InputStreamReader isr=new InputStreamReader(fis,"gbk");//ANSI
InputStreamReader isr=new InputStreamReader(fis,"utf-8");
//读取文件
char[] buf=new char[1024];
int len=-1;
while ((len=isr.read(buf))!=-1){
String str=new String(buf,0,len);
System.out.println(str);
}
//关闭
isr.close();
}
}
1.2字节转换输出流(OutputStreamWriter)
// 使用转换流写入内容
public class Demo6 {
public static void main(String[] args) throws Exception{
//创建转换输出流
FileOutputStream fos=new FileOutputStream("e:dd.txt");
//OutputStreamWriter osw=new OutputStreamWriter(fos,"gbk");
OutputStreamWriter osw=new OutputStreamWriter(fos,"utf-8");
//写入
for (int i = 0; i < 10; i++) {
osw.write("今天晚上不上晚自习,那是不可能的\r\n");
osw.flush();
}
//关闭
osw.close();
System.out.println("写入完毕");
}
}
二.缓冲流
2.1字节流
2.1.1字节输入缓冲流(BufferedInputStream)
//BufferedInputStream,字节输入缓冲流
FileInputStream fis=new FileInputStream("hello.txt");
BufferedInputStream bis=new BufferedInputStream(fis);
//2.读取
byte[] buf=new byte[1024*4];
int len=0;
while ((len=bis.read(buf))!=-1){
String str=new String(buf,0,len);
System.out.println(str);
}
//关闭
bis.close();
2.1.2字节输出缓冲流(BufferedOutputStream)
//BufferedOutputStream 字节输出缓冲流
//创建缓冲流
FileOutputStream fos=new FileOutputStream("out.txt");
BufferedOutputStream bos=new BufferedOutputStream(fos);
//写入
for (int i = 0; i < 10; i++) {
//现在还在缓冲区里,没有写入硬盘上
bos.write("好好学习,天天向上\r\n".getBytes());//可以指定编码
bos.flush();
}
bos.close();
System.out.println("写入完毕");
2.1.3综合案例1
// 使用缓冲流实现文件的复制
//创建缓冲流
BufferedInputStream bis=new BufferedInputStream(new
FileInputStream("out.txt"));
BufferedOutputStream bos=new BufferedOutputStream(new
FileOutputStream("out2.txt"));
//读写
byte[] buf=new byte[1024*4];
int len=-1;
while((len=bis.read(buf))!=-1){
bos.write(buf,0,len);
bos.flush();
}
//关闭
bos.close();
bis.close();
System.out.println("复制完毕");
2.2字符流
BufferedReader类:
实例化缓冲字符流的对象 BufferedReader reader = new BufferedReader(new
FileReader(file));
BufferedWriter类:
实例化缓冲字符输出流 BufferedWriter writer = new BufferedWriter(new
FileWriter(file,true));
2.2.1字符缓冲输入流(BufferedReader)
//BufferedReader 字符缓冲输入流
public class Demo3 {
public static void main(String[] args) throws Exception{
//创建对象
FileReader fr=new FileReader("out.txt");
BufferedReader br=new BufferedReader(fr);
//读取
/*//使用char数组
char[] buf=new char[1024];
int len=-1;
while ((len=br.read(buf))!=-1){
System.out.println(new String(buf,0,len));
}*/
/*//使用readLine()读取一行
String line=br.readLine();
System.out.println(line);*/
//读取多行
String line=null;
while ((line=br.readLine())!=null){
System.out.println(line);
}
//关闭
br.close();
}
}
2.2.2字符缓冲输出流(BufferedWriter)
// BufferedWriter使用字符缓冲输出流
public class Demo4 {
public static void main(String[] args) throws Exception{
//创建对象
FileWriter fw=new FileWriter("buf.txt");
BufferedWriter bw=new BufferedWriter(fw);
//写入
for (int i = 0; i < 10; i++) {
bw.write("我爱java");
bw.newLine();//行终止符 windows \r\n linux \n
bw.flush();
}
//关闭
bw.close();
}
}
三.内存流
此时的操作应该以内存为操作点
ByteArrayInputStream: 内存输入流,将内容写入到内存中,是Inputstream的子类
//定义一个字符串,全部由大写字母组成 。注意不要写中文,否则要进行转换
String string = "HELLOWORLD";
//向内存中输出内容,注意:跟文件读取不一样,不设置文件路径
ByteArrayInputStream bis = new ByteArrayInputStream(string.getBytes());
ByteArrayOutputStream:将内存中数据输出,是OutputStream的子类
//准备从内存中读取内容,注意:跟文件读取不一样,不设置文件路径
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//循环结束之后,所有的数据都在ByteArrayOutputStream中
//取出内容,将缓冲区内容转换为字符串
String newString = bos.toString();
3.1字节数组输入流(ByteArrayInputStream)
// ByteArrayInputStream 字节数组输入流
public class Demo5 {
public static void main(String[] args) throws Exception{
byte[] data="abcdefg".getBytes();
//创建字节数组输入流
ByteArrayInputStream bais=new ByteArrayInputStream(data);
//读取
int d=0;
while ((d=bais.read())!=-1) {
System.out.print((char)d);
}
//关闭(可以不用关)
bais.close();
}
}
3.2字节数组输出流(ByteArrayOutputStream)
// ByteArrayOutputStream 字节数组输出流
public class Demo6 {
public static void main(String[] args) throws Exception{
//创建字节数组输出流
ByteArrayOutputStream baos=new ByteArrayOutputStream();
//写入---写内存里了(数组),需要先取出来
for (int i = 0; i < 10; i++) {
baos.write("hello".getBytes());
}
//关闭
baos.close();
//获取数组
String s=baos.toString();
System.out.println(s);
}
}
3.3综合案例2
// 案例:完成字母大小写转换的程序,使用内存流
public class Demo7 {
public static void main(String[] args) throws Exception{
String str="HELLO WORLD";
//创建流
ByteArrayInputStream bais=new ByteArrayInputStream(str.getBytes());
//转换流InputStreamReader isr=new InputStreamReader(bais);
ByteArrayOutputStream baos=new ByteArrayOutputStream();
//转换流OutputStreamWriter osw=new OutputStreamWriter(baos);
//读取写入
int d=-1;
while ((d=bais.read())!=-1){//d=isr....
//若是中文字符串,这个c会有问题,需要用一下转换流
char c=Character.toLowerCase((char)d);
baos.write(c);//转换流osw.weite(c);osw.flush();
}
//关闭
bais.close();
baos.close();
//获取数组
String str2=baos.toString();
System.out.println(str2);
}
}
四.标准输入输出流
Java的标准输入/输出分别通过System.in和System.out实现,默认情况下分别代表是键盘和控制台
PrintStream类:PrintStream为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
PrintWriter类:向文本输出流打印对象的格式化表示形式。此类实现在 PrintStream中的所有 print方法。它不包含用于写入原始字节的方法。
4.1 System.in:BufferedInputStream
// System.in:BufferedInputStream
public class Demo8 {
public static void main(String[] args) throws Exception{
/*System.out.println(System.in.getClass().getName());
//结果:java.io.BufferedInputStream
System.out.println(System.out.getClass().getName());
//结果:java.io.PrintStream*/
//获取流
// 运行后等着从控制台输入,回车后就能读出了
// 程序不会结束,会一直等待从控制台输入,只能强制退出,或者使用判断语句
// 换行和回车也会被打出来,换行:10,回车:13,回车被隐藏
InputStream is=System.in;
/*//读取数据,读取一个
int d=is.read();
System.out.println((char)d);*/
//读取多个
int d=-1;
StringBuilder sb=new StringBuilder();
while ((d=is.read())!=-1){
if (d==13){
continue;
}
if (d==10){//读取了一行
System.out.println(sb.toString());
if (sb.toString().equals("over")){
break;//跳出循环
}
//清空
sb.delete(0, sb.length());
}else {
sb.append((char)d);
}
//System.out.print((char)d);
}
//关闭,也可以不用关
is.close();
}
}
4.2 System.out:BufferedOutputStream
// 按行读取,实现控制台输入
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
/*//2.读取
String line=br.readLine();
System.out.println(line);*/
String line=null;
while (true){
line=br.readLine();
System.out.println(line);
if (line.equals("over")){
break;
}
}
//关闭
br.close();
4.3 PrintStream和PrintWriter
4.3.1打印数据
// 使用PrintStream打印数据:字节流; PrintWriter:字符流.本案例结果相同
// 文件---硬盘(外部),java程序---内存(内部)
public class Demo10 {
public static void main(String[] args) throws Exception{
//创建打印流
PrintStream ps=new PrintStream("print.txt");
PrintWriter pw=new PrintWriter("printw.txt");
//打印,ps.write(97)输出a
ps.write(97);ps.println();
//原样输出
ps.println(97);ps.println(3.14);ps.println(true);ps.println("我爱java");
//关闭
ps.close();
//打印
pw.write(97); pw.println();
//原样输出
pw.println(97); pw.println(3.14); pw.println(true);pw.println("我爱java");
//关闭
pw.close();
}
}
4.3.2重定向标准输出流
默认是输出到控制台
// 重定向标准输出流
public class Demo11 {
public static void main(String[] args) throws Exception{
System.out.println("hello");
//给System.out重新初始化,使输出到SystemOut.txt中
PrintStream ps=new PrintStream("SystemOut.txt");
System.setOut(ps);
for (int i = 0; i < 10; i++) {
System.out.println("好久不见");
}
ps.close();
}
}
五.对象流
输出:序列化(内存—>硬盘):将一个对象写入到本地文件中
ObjectInputStream:对象输出流
输入:反序列化(硬盘—>内存):将一个本地文件中的对象读取出来
ObjectOutputStream:对象输入流
注意:
序列化对象的类型必须实现Serializable接口。否则不能序列化。
如果向将多个对象序列化到本地,可以借助于集合。
在使用对象流的时候,用于初始化对象流的参数只能是字节流(将对象转换为二进制的形式,然后再把二进制写入文件)
不可以序列化:
1 transient 修饰的字段:瞬间的
2 静态的字段
在序列化类中添加字段,保证序列化和反序列化是同一个类,否则,若像序列类中添加字段,反序列化会认为不是同一个序列类,会报异常
private static final long serialVersionUID = 100L;
// 使用ObjectOutputStream实现序列化
// 使用ObjectIntputStream实现反序列化
public class Demo12 {
public static void main(String[] args) throws Exception{
writeObject();
readObject();
}
public static void writeObject() throws Exception{
//创建流
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("stu.bin"));
//序列化
Student shaobo=new Student("少泊",16,"北京");
Student zhagnsan=new Student("张三",16,"北京");
Student lisi=new Student("李四",16,"北京");
ArrayList<Student> list=new ArrayList<>();
list.add(shaobo);
list.add(zhagnsan);
list.add(lisi);
oos.writeObject(list);
//oos.writeObject(shaobo);
//关闭
oos.close();
System.out.println("序列化完毕");
}
public static void readObject() throws Exception{
//创建流
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("stu.bin"));
//读取
/* Student stu=(Student)ois.readObject();*/
ArrayList<Student> list=(ArrayList<Student>)ois.readObject();
for (Student student : list) {
System.out.println(student.toString());
}
/*System.out.println(stu.toString());*/
//关闭
ois.close();
System.out.println("反序列化完毕");
}
}
六.RandomAccessFile类
支持对随机访问文件的读取和写入
RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了。这些记录的大小不必相同;但是其大小和位置必须是可知的。但是该类仅限于操作文件。
// 使用RandomAccessFile读写文件
public class Demo1 {
public static void main(String[] args) throws Exception{
write();
read();
}
public static void write() throws Exception{
//创建对象
RandomAccessFile raf=new RandomAccessFile("ran.txt", "rw");
//写入
raf.writeUTF("张三");
raf.writeInt(20);
raf.writeDouble(170.5);
raf.writeBoolean(true);
raf.writeUTF("李四");
raf.writeInt(21);
raf.writeDouble(171.5);
raf.writeBoolean(false);
//关闭
raf.close();
System.out.println("写入完毕");
}
public static void read() throws Exception{
RandomAccessFile raf=new RandomAccessFile("ran.txt", "rw");
//设置跳过张三,设置读取指针的偏移量,从0开始,
//李四:0006+6个字节;21:占4个字节;171.5:占8个字节;false:占1个字节
//raf.seek(21);
//跳过21个字节,从当前位置开始跳
raf.skipBytes(21);
String name=raf.readUTF();
int age=raf.readInt();
Double high=raf.readDouble();
boolean b=raf.readBoolean();
System.out.println(name+" "+age+" "+high+" "+b);
//关闭
raf.close();
}
}
七.Properties类
properties可保存在流中或从流中加载,属性列表中每个键及其对应值都是一个字符串
是Map接口的一个实现类,并且是Hashtable的子类
Properties集合中元素也是以键值对的形式存在的
// 使用Properties集合保存数据
public class Demo2 {
public static void main(String[] args) throws Exception{
//创建集合
Properties properties=new Properties();
//添加
properties.setProperty("name","少泊");
properties.setProperty("age", "20");
properties.setProperty("address", "北京");
//遍历
Set<String> keyset=properties.stringPropertyNames();
for (String key : keyset) {
System.out.println(key+"----"+properties.getProperty(key));
}
//和流有关的方法
//1.list方法
System.out.println("----list------");
properties.list(new PrintStream("prop.properties"));
System.out.println("输出到控制台:");
properties.list(System.out);
//2.load方法:加载
System.out.println("-----load-------");
Properties properties1=new Properties();
properties1.load(new FileReader("prop2.properties"));
properties1.list(System.out);
//store方法
properties.store(new FileWriter("prop3.properties"), "信息");
//System.getProperties
Properties sysprop=System.getProperties();
sysprop.setProperty("myname", "hello");//加入自己的配置
sysprop.list(System.out);
}
}
八.装饰者设计模式
扩展类的功能的方法:
(1)继承并重写,缺点:耦合性高
(2)装饰者设计模式
(3)动态代理
装饰模式指的是在不必改变原类文件和继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
应用场景:需要扩展一个类的功能,或给一个类添加附加职责。
8.1示例1:读取文件
public class RBDemo1 {
public static void main(String[] args) {
ReadText readText=new ReadText();
BufferedReadFile bufferedReadFile=new BufferedReadFile(readText);
bufferedReadFile.read();
}
}
// 抽象类:读取文件
public abstract class ReadFile {
public abstract void read();
}
public class ReadText extends ReadFile{
@Override
public void read() {
System.out.println("读取文本文件");
}
}
public class BufferedReadFile {//extends ReadFile
private ReadFile readFile;
public BufferedReadFile(ReadFile readFile) {
this.readFile = readFile;
}
public void read(){
System.out.println("带缓冲读取文件");
readFile.read();
}
}
8.2示例2:人吃饭
public class Demo1 {
public static void main(String[] args) {
Student shaobo=new Student();
Teacher laowang=new Teacher();
StrongPerson strongPerson=new StrongPerson(shaobo);
StrongPerson strongPerson1=new StrongPerson(laowang);
strongPerson.eat();
strongPerson1.eat();
}
}
public abstract class Person {
public abstract void eat();
}
public class StrongPerson {
private Person person;
public StrongPerson(Person person) {
this.person = person;
}
public void eat(){
System.out.println("喝两口...");
person.eat();
System.out.println("抽两口");
System.out.println("睡一会...");
System.out.println("玩一会...");
}
//添加新的功能
public void play(){
System.out.println("xx");
}
}
public class Student extends Person {
@Override
public void eat() {
System.out.println("学生吃饭");
}
}
public class Teacher extends Person {
@Override
public void eat() {
System.out.println("老师吃东西");
}
}