JAVA---字符流

雨燕双飞 提交于 2020-03-16 15:25:34

目录

文件写入:

方式一:flush()

 方式二:colse()

flush()和colse()区别:

规范示例:

对已有文件进行续写

文件的读取

方式一:read()

方式二:read(char[])

拷贝文件:

字符流的缓冲区

BufferedWriter

BufferedReader

示例:

装饰者模式:

继承和装饰的区别:

实景应用:

自定义装饰类


文件写入:

方式一:flush()

字符输出流在输出内容的时候,比如写文件的时候,是先写入缓冲区,当缓冲区满之后再写入文件,如此往复,但是当某次输出比如在最后输出的内容不能填满一个缓冲区,那么就会一直等待,所以这时需要进行强制写入文件,将缓冲区内容清空到文件中

public static void main(String[] args) throw IOException   //FileWriter()会抛异常
{
    //创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件,而且该文件会被创建到指定目录下,如果该目录下已有同名文件,将被覆盖,其实该步就是在明确数据要存放的目的地
    FileWriter fw=new FileWriter("demo.txt");
    
    //调用write方法,将字符串写入到流中
    fw.write("abc");

    //刷新流对象中的缓冲中的数据
    //将数据刷到目的地中
    fw.flush();
      
}

 方式二:colse()

public static void main(String[] args) throw IOException   //FileWriter()会抛异常
{
    //创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件,而且该文件会被创建到指定目录下,如果该目录下已有同名文件,将被覆盖,其实该步就是在明确数据要存放的目的地
    FileWriter fw=new FileWriter("demo.txt");
    
    //调用write方法,将字符串写入到流中
    fw.write("abc");
    

    //关闭流资源,但是关闭前会刷新一次内部的缓冲中的数据,将数据刷到目的地中
    fw.colse();
}

flush()和colse()区别:

flush刷新后,流可以继续使用,colse()刷新后,会将流关闭

规范示例:

Class FileWriteDemo
{
    public static void main(String[] args)
    {
        //只有定义在这finally里面才能访问fw
        FileWriter fw=null;

        try
        {
            //FileWriter()初始化会抛异常
            fw.=new FileWriter("demo.txt");
            fw.write("abc");
        }
        catch
        {
            System.out.printlm("catch:"+e.toString());
        }
        finally
        {
            //不管发生什么,都要关闭资源
            try
            {
                //FileWriter()初始化异常,对象不存在,就会抛出两个异常,为了解决这个问题,只抛出一个异常,就来个判断,如果有多个对象,就需要多个try和if判断
                if(fw!=null)
                    fw.close();
            }
            catch(IOException e)
            {
                System.out.println(e.toString());
            }
        }
    }
}

对已有文件进行续写

public static void main(Stirng[] agrs) throws IOException
{
    //传递一个ture参数,代表不覆盖已有的文件,并在已有文件的末尾处进行数据续写
    FileWriter fw =new FileWriter("demo.txt",true);
    
    fw.write("nihao");
    fw.close();
}

文件的读取

方式一:read()

读取单个字符

class FileReaderDemo
{
    pbulic static void main(String[] args) throws IOException
    {
        //创建一个文件读取流对象,和指定名称的文件相关联。
        //要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException
        FileReader fr = new FileReader("demo.txt");

        //调用读取流对象的read方法
        //read():一次读一个字符,而且会自动往下读

        int ch=0;
    
        //为什么是-1,因为在磁盘读取的时候,数据是连续存储在磁盘中的,而数据之间通过分隔符来分割,磁盘一识别分隔符的位置,就返回信息-1说明读完了
        while((ch=fr.read())!=-1)
        {
            System.out.println((char)ch);
        }
    }
}

方式二:read(char[])

通过字符数组进行读取

class FileReaderDemo
{
    pbulic static void main(String[] args) throws IOException
    {
        
        FileReader fr = new FileReader("demo.txt");

        //定义一个字符数组,用于存储读到字符
        //该read(char[])返回的是读到字符个数
        char[] buf =new char[1024];


        int num=0;
    
        while((num=fr.read(buf))!=-1)
        {
             //读取从0到num的字符
            System.out.println(new String(buf,0,num));
        }
    
        fr.close();
    }
}

拷贝文件:

/*
复制原理:其实就是将C盘下的文件数据存储到D盘的一个文件中
步骤:
1.在D盘创建一个文件,用于存储C盘文件中的数据
2.定义读取流和C盘文件关联
3.通过不断地读写完成数据存储
4.关闭资源
*/

import java.io.*;

class CopyText
{
    public static void main(String[] args)
    {
        copy();
    }

    public static void copy()
    {
        FileWriter fw =null;
        FileReader fr =null;
    
        try
        {
            fw =new FileWriter("SystemDemo_copy.txt");

            fr=new FileReader("SystemDemo.java");

            char[] buf =new char[1024];
            int len=0;
            while(len=fr.read(buf)!=-1)
            {
                fw.write(buf,0,len);
            }
        catch(IOException e)
        {
            throw new RuntimeException("读写失败");
        }
        finally
        {
            if(fr!=null)
            {
                fr.close();
            }
            catch(IOException e)
            {
            }

            if(fw!=null)
            {
                fr.close();
            }
            catch(IOException e)
            {
            }
        }

        }
        
    }
}

 

字符流的缓冲区

  • 缓冲区的出现提高了对数据的读写效率
  • 对应类
    • BufferedWriter
    • BufferedReader 
  • 缓冲区要结合流才能使用
  • 在流的基础上对流的功能进行增强
  • 在创建缓冲区之前,必须要先有流对象

什么是缓冲区:

内存里的一块区域,把数据先存内存里,然后一次性写入,类似数据库的批量操作,这样效率比较高。

BufferedWriter

class BufferedWeiterDemo 
{
    public static void main(String[] args) throws IOException
    {
        //创建一个字符写入流对象
        FileWriter fw =new FileWriter("buf.txt");
    
        //为了提高字符写入流效率,加入了缓冲技术
        //只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可
        BufferedWriter bufw =new BufferedWriter(fw);
        
        for(int x=1;x<5;x++)
        {
            bufw.write("abc"+x);
            //该缓冲区中提供了一个跨平台的换行符
            bufw.newLine();
            //只要用到缓冲区,就要记得刷新
            bufw.flush();
        }
        
        //其实关闭缓冲区,就是在关闭缓冲区中的流对象
        bufw.close();
        

    }
}

//输出
abc1
abc2
abc3
abc4

以上是一行一行刷新到文本中的

 

BufferedReader

字符串读取流缓冲区

该缓冲区提供了一个一次读一行的方法,readline,方便于文本数据的获取,当返回null时,表示读到文件末尾

readLine()方法返回的时候只返回回车符之前的数据内容,并不返回回车符(在一行的文本后面会有/r/n,作用是windows系统下的换行功能)

class BufferedReaderDemo 
{
    public static void main(String[] args) throws IOException
    {
        //创建一个读取流对象和文件相关联
        FileReader fr =new FileReader ("buf.txt");
    
        //为了提高效率,加入了缓冲技术,将字符读取流对象作为参数传递给缓冲对象的构造函数
        BufferedReader bufr =new BufferedReader(fr);
        
        String line=null;

        while(line=bufr.readLine()!=null)
        {
            System.out.println(line);
        }
        
        
        bufr.close();
        

    }
}

//输出
abc1
abc2
abc3
abc4

示例:

通过缓冲区复制文本文件

class CopyTextByBuf
{
    public static void main(String[] args) throws IOException
    {
        BufferedReader bufr = null;
        BufferedWriter bufw = null;

        try
        {
            bufr = new BufferedReader(new FileReader("BufferedWriterDemo.java"));    
            bufw = new BufferedWriter(new FileWriter("bufWriter_Copy.txt"));

            String ling=null;
    
            while((line =bufr.readLine())!=null)
            {
                bufw.write(line);
                bufw.newLine();
                bufw.flush();
            }
        }
        catch(IOException e)
        {
            throw new RuntimeException("读写失败");
        }
        finally
        {
            try
            {
                if(bufr!=null)
                    bufr.close();
            }
            catch(IOException e)
            {
                throw new RuntimeException("读写关闭失败");
            }

            try
            {
                if(bufw!=null)
                    bufw.close();
            }
            catch(IOException e)
            {
                throw new RuntimeException("写入关闭失败");
            }
        }

    }
}

ReadLIne原理

明白了BufferedReader类中特有方法readLine原理后,可以自定义一个类中包含一个功能和readLine一致的方法,来模拟一下BufferedReader

class MyBufferedReader
{
    private FileReader r;
    MyBufferedReader(FileReader r)
    {
        this.r=r;
    }
    
    //可以一次读一行数据的方法
    public String myReadLine() throws IOException
    {
        //定义一个临时容器,原BufferReader封装的是字符数组
        //为了演示方便,定义一个StringBuilder容器,因为最终还是要将数据变成字符串
        StringBuilder sb =new stringBuilder();
    
        int ch=0;
        while((ch=r.read())!=-1)
        {
            if(ch=='/r')
                continue;
            if(ch=='/n')
                return sb.toString();
            else
                sb.append((char)ch);
        }
        //因为在最后一行没有/n,只有/r,所以要将最后一行的数据显示出来,需要写这行代码
        if(sb.length()!=0)
            return sb.toString();
        return null;
    }
    public void myClose() throws IOException
    {
        //缓冲区实际关闭的是流对象,所以关闭了缓冲区,就不用在关闭流对象了
        r.close();
    }
}

class MyBufferedReaderDemo 
{
    public static void main(String[] args) throws IOException
    {
        //创建一个读取流对象和文件相关联
        FileReader fr =new FileReader ("buf.txt");
    
        //为了提高效率,加入了缓冲技术,将字符读取流对象作为参数传递给缓冲对象的构造函数
        MyBufferedReader mybufr =new MyBufferedReader(fr);
        
        String line=null;

        while(line=mybufr.readLine()!=null)
        {
            System.out.println(line);
        }
        
        
        mybufr.close();
        

    }
}

装饰者模式:

当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能,那么自定义的该类成为装饰类

class Person
{
    public void eat()
    {
         System.out.println("吃饭");
    }
}

class SuperPerson
{
    private Person p;
    SuperPerson(Person p)
    {
        this.p=p;
    }
    public void superEat()
    {
        System.out.println("开胃菜");
        p.eat();
        System.out.println("甜点");
        System.out.println("水果");
    }
}

class PersonDemo
{
    public static void main(String[] args)
    {
        Person p=new Person();

        SuperPerson sp =new SuperPerson(p);
        sp.superEat();
    }

}

装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能

 

继承和装饰的区别:

  • 装饰模式比继承要灵活,避免了继承体系臃肿,而且降低了类与类之间的关系
  • 装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰类通常是属于一个体系的
  • 谁用谁进来,装饰就是为了提高别人效率而存在的

实景应用:

当你进入一个公司,要用到一个人的功能,就用个装饰着模式,进行扩展,也不会影响到它地代码,安全,而且可以对它地代码进行扩展并应用,不会像继承那样臃肿

继承体系

装饰者模式:

自定义装饰类

将传入的对象改为Reader(这个体系的父类),这样就可以传这个体系中的任意类型的对象,还要继承于Reader,还要重写其内部的抽象方法

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!