Java学习笔记——流操作

缓冲流

作用:主要是为了增强基础流的功能而存在的,提高了流的工作效率【读写效率】

注意:如果使用记事本创建的文件,文件是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(){
           ///
         }
     }

你可能感兴趣的:(Java基础)