IO流 整理

来源:互联网 发布:开淘宝网店的流程2016 编辑:程序博客网 时间:2024/06/14 10:55

引入

io流是操作数据(主要是控制台,和内存中)、文件(硬盘中)的流对象。
引用的包是java.io.*

  • 按流向分为:输入流和输出流。

  • 按操作数据分为:字节流和字符流

    字节流的抽象基类:InputStream,OutputStream
    字符流的抽象基类:Reader,Writer
    注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀

如:InputStream的子类FileInputStream。 Reader的子类FileReader。

字符流

简单的字符流。

//一个一个字符打印FileReader fr=new FileReader(“hello.txt”);int ch;while((ch=fr.read())!=-1){System.out.println((char)ch);}
//指定长度字符串打印FileReader fr=new FileReader(“hello.txt”);char[] chs=new char[1024];int length;//一次读了多少长度的字符串while(length=fr.read(chs));{//取对应读取长度的字符串长度。System.out.println(new String(chs,0,length));}
//没有该文件则创建,有该文件则覆盖FileWriter fw=new FileWriter(“hello.txt”);//没有该文件创建,有该文件则续写。//FileWriter fw=new FileWriter(“hello.txt”,true);fw.write(“dddgfwe”);fw.flush();fw.close();

在IO中最必要的就是有IO异常,需要对异常处理,或者抛出,下面是对异常完整处理的代码。

  • 读加写 完整异常处理

FileDemo.java

import java.io.*;class FileDemo{    public static void main(String[] args) {    //在try的外面声明对象,使该对象是存在的,如果try中抛出了异常,对象也能被finally被使用!        FileReader fr=null;        FileWriter fw=null;        try{        //这里使用读文件和写文件,所以都会抛异常。            fr=new FileReader("FileReaderDemo.java");            fw=new FileWriter("copy.txt");            char[] ch=new char[1024];            int len=0;            while((len=fr.read(ch))!=-1){                fw.write(ch,0,len);                }                fw.flush();            }catch (IOException e){                System.out.println(e);            }finally{                try{                    /*关流也存在异常。但是为了减少异常的出现,我们可以在关流之前对对象进行判空,如果是空那么那么无需关闭。当然需要分别判空*/                    if (fr==null) {                        fr.close();                    }                    if (fw==null) {                        fw.close();                    }                }catch (IOException e){                    System.out.println(e);                }            }    }}

tip.在windows中 换行是”/r/n”

能够对文件进行读写之后,我们希望能够提高速度,所以缓冲流就引入了。

  • 读加写 缓冲流 异常处理

可以注意下缓冲流中对换行已经封装好了。

BufferedWriterDemo.java

import java.io.*;class BufferedWriterDemo{    public static void main(String[] args)throws IOException{        BufferedReaderAndWriter_Method();    }//写    public static void BufferedWriter_Method()throws IOException{        FileWriter fw=new FileWriter("xx.txt");        BufferedWriter bw=new BufferedWriter(fw);        bw.write("sjhhs");        //封装好了换行,好处,可以跨操作系统使用。        bw.newLine();        bw.write("311");        bw.flush();        bw.close();    }    public static void BufferedReader_Method()throws IOException{        FileReader fr=new FileReader("xx.txt");        BufferedReader br=new BufferedReader(fr);        String aa=null;        //封装了读一整行,而且是不带换行符号的(windows系统中的"\r\n")        //返回类型直接是String类型,便于操作        while((aa=br.readLine())!=null){            System.out.println(aa);        }        br.close();    }//缓冲流读加写,并且异常处理     public static void BufferedReaderAndWriter_Method(){        BufferedReader br=null;        BufferedWriter bw=null;        try{            br=new BufferedReader(new FileReader("FileDemo.java"));            bw=new BufferedWriter(new FileWriter("copy2.txt"));            String line=null;            while((line=br.readLine())!=null){                bw.write(line);                bw.newLine();                bw.flush();            }        }catch (IOException e){            System.out.println(e);        }finally{            try{                if (bw!=null) {                    bw.close();                }                if (br!=null){                    br.close();                }            }catch(IOException e){                System.out.println(e);            }        }    }}

缓冲流的使用其实是一种装饰模式。文章的末尾会浅谈一番。

BufferedWriter中的newLine()封装的是打印换行的转译字符(所以在windows系统和linux系统都可以使用);
BufferedReader中的readLine()封装的是通过read()方法一个一个字符读取,总合一行的字符(直到字符为换行字符即“/r/n”),则返回一行的字符串,不包含转译字符。

我们可以自己试着书写一个缓冲输入流。

MyBufferedReaderDemo.java

import java.io.*;class MyBufferedReaderDemo{    public static void main(String[] args)throws IOException{        FileReader fr=new FileReader("xx.txt");        MyBufferedReader mbr=new MyBufferedReader(fr);        String line=null;        while((line=mbr.myRead())!=null){            System.out.println(line);            }        if (mbr!=null) {            mbr.myClose();        }    }}class MyBufferedReader{    private FileReader f;    //构造函数值得注意一下    MyBufferedReader(FileReader f){        this.f=f;    }    public String myRead()throws IOException{        StringBuilder sb=new StringBuilder();        int ch = 0;        while((ch=f.read())!=-1){            if(ch=='\r')                continue;            if(ch=='\n')                return sb.toString();            else                sb.append((char)ch);        }        if (sb.length()!=0)            return sb.toString();        return null;        }//当然也需要覆写关流    public void myClose()throws IOException{        f.close();    }}

字节流

同样看读写,以及使用缓存的例子

public static void method_1()throws IOException{        FileOutputStream fos=new FileOutputStream("ceshi.txt");        fos.write(("dasgxc").getBytes());//与字符流不同的是:这里没有刷缓存!//资源是需要关闭的,是占用资源的        fos.close();    }

在FileOutputStream中的write所写的是最小单位,不需要刷新,直接传输,没有任何转换。

FileWriter所使用的write方法经过封装,底层使用的是FileOutputStream,是将一个字符分解为一个个字节来传输的,所以它是需要刷新缓存。

//一个一个字节读取。    public static void method_2()throws IOException{        FileInputStream fis=new FileInputStream("ceshi.txt");        int b=0;        while((b=fis.read())!=-1){            System.out.println((char)b);        }    }
//一串字节读取。    public static void method_3()throws IOException{        FileInputStream fis=new FileInputStream("ceshi.txt");        byte[] b=new byte[1024];        int len=-1;        while((len=fis.read(b))!=-1){            System.out.println(new String(b,0,len));        }    }
//设置一个与复制目标文件相同大小的字节数组,将这串字节数组一起打印,所以只需要一次,不用循环。//但是,当目标文件过大时,会使内存爆炸,如比内存还大,内存中就装不下这样的数组了。    public static void method_4()throws IOException{        FileInputStream fis=new FileInputStream("ceshi.txt");        //得到文件的大小        int size=fis.available();        byte[] b=new byte[size];        fis.read(b);        System.out.println(new String(b));    }

字节流缓冲读写

    public static void method_5()throws IOException{        BufferedInputStream bis=new BufferedInputStream(new FileInputStream("ceshi.txt"));        BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("ceshi2.txt"));        int by=0;        while((by=bis.read())!=-1){            bos.write(by);        }        bis.close();        bos.close();    }
  • 通过字节流复制一个mp3文件。
    CopyMp3.java
import java.io.*;class CopyMp3{    public static void main(String[] args) throws IOException{        long start =System.currentTimeMillis();        // MyBufferedInputStream mbis=new MyBufferedInputStream(new FileInputStream("1.mp3"));        BufferedInputStream mbis=new BufferedInputStream(new FileInputStream("1.mp3"));        BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("2.mp3"));        int i=0;        while((i=mbis.myRead())!=-1){            bos.write(i);        }        bos.close();        mbis.myClose();        long end =System.currentTimeMillis();        System.out.println((end-start)+"毫秒");    }}

自己写一个读mp3的字节流,当然是使用缓冲流提速的!
MyBufferedInputStream.java

import java.io.*;class MyBufferedInputStream{    private InputStream in;    private int pos=0,count=0;    private byte[] b=new byte[1024*1024];    MyBufferedInputStream(InputStream in){        this.in=in;    }    public int myRead()throws IOException{        if (count==0) {            count=in.read(b);            pos=0;            if (count<0) {                return -1;            }            // System.out.println("length:"+b.length+"   count:"+count+"  pos:"+pos);            byte bt=b[pos];            count--;            pos++;            //注意这里并上了一个255。            return bt&255;            }        else if (count>0) {            // System.out.println("length:"+b.length+"   count:"+count+"  pos:"+pos);            byte bt=b[pos];            count--;            pos++;            return bt&255;            }        return -1;    }    public void myClose()throws IOException{        in.close();    }}

由于二进制转换为int的时候,为防止出现连续的八个1(1111 1111 即可以表示255也可以表示-1,而在判断条件是,read()==-1,表示读到了文件的末尾,出现冲突,可能会提前结束读的操作)。
所以转换时,存在着提升的现象,在每个8位二进制的数值前,补上三组八个0,使其区分于“-1”的二进制(32个1)表示。即
一个字节(8位)&0000 0000 0000 0000 0000 0000 1111 1111(255)。

修改CopyMp3.java

import java.io.*;class CopyMp3{    public static void main(String[] args) throws IOException{        long start =System.currentTimeMillis();        MyBufferedInputStream mbis=new MyBufferedInputStream(new FileInputStream("1.mp3"));        //BufferedInputStream mbis=new BufferedInputStream(new FileInputStream("1.mp3"));        BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("2.mp3"));        int i=0;        while((i=mbis.myRead())!=-1){            bos.write(i);        }        bos.close();        mbis.myClose();        long end =System.currentTimeMillis();        System.out.println((end-start)+"毫秒");    }}

装饰设计模式

现在我们来浅谈一番 装饰设计模式

老师的定义:想要对已有的对象进行功能强化时,可以定义类,将已有对象传入,基于已有的功能,并提供加强的功能。那么称这个类为装饰类。

首先,这是装饰,所以他是服务的,而不是自己有的,那么它就没有空的构造函数,它只有有参的构造函数。

并且,前面提到的参数是所要装饰的对象,作为该装饰类的私有属性,通过构造函数来初始化。

提示:参数最好可以使用父类或者基类。使用一个基类,可以使它不同的子类作为入参,可以以多态的形式实现,而且降低了具体的子类和装饰类的耦合关系。

BufferedReader是Reader的装饰类。
而LineNumberReader也是Reader的装饰类,它同样是BufferReader的子类,所以部分代码在BufferedReader基础上面有拓展。

原创粉丝点击