IO流 整理

引入

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基础上面有拓展。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值