Java IO流 装饰 字节流--19

来源:互联网 发布:淘宝店怎么卖充值卡 编辑:程序博客网 时间:2024/06/08 12:36

缓冲区

缓冲区的出现是为了提高流的操作效率而出现的

所以在创建缓冲区之前,必须要现有流对象。

该缓冲区提供了一个跨平台的换行符

newLine();

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

字符读取流缓冲区

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

readLine方法的原理:
无论是读一行,或者读取多个字符,其实最终都是在硬盘上一个一个的读取,所以最终使用的还是read方法一次读一个的方法

readLine方法返回的时候只返回回车符之前的数据内容,并不返回回车符

import java.io.*;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();    }}

这里写图片描述

通过缓冲区复制一个.java文件

import java.io.*;class CopyTestByBuf{    public static void main(String[] args)    {        BufferedReader bufr = null;        BufferedWriter bufw = null;        try        {            bufr = new BufferedReader(new FileReader("BufferedWriterDemo.java"));            bufw = new BufferedWriter(new FileWriter("bufWriter_Copy.txt"));            String line = 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("写入关闭失败");            }        }    }}

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

import java.io.*;class MyBufferedReader{    private FileReader r;    MyBufferedReader(FileReader r)    {        this.r = r;    }    //可以一次读一行数据的方法    public String myReadLine()throws IOException    {        //定义一个临时容器,原BufferedReader中封装的是字符数组        //为了演示方便,定义一个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);        }        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("bufWriter_Copy.txt");        MyBufferedReader myBuf = new MyBufferedReader(fr);        String line = null;        while((line=myBuf.myReadLine())!=null)        {            System.out.println(line);        }        myBuf.myClose();    }}

装饰类

装饰设计模式

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

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

吃饭的例子:

class Person{    public void chifan()    {        System.out.println("吃饭");    }}class SuperPerson{    private Person p;    SuperPerson(Person p)    {        this.p = p;    }    public void superChifan()    {        System.out.println("开胃酒");        p.chifan();        System.out.println("甜点");    }}class PersonDemo{    public static void main(String[] args)    {        Person p = new Person();        //p.chifan();        SuperPerson sp = new SuperPerson(p);        sp.superChifan();    }}

装饰模式与继承的比较

MyReader//专门用于读取数据的对象
|–MyTextReader
|–MyBufferTextReader
|–MyMediaReader
|–MyBufferMediaReader
|–MyDataReader
|–MyBufferDataReader

class MyBufferReader
{
MyBufferRead(MyDataReader data)
{}
MyBufferRead(MyMediaReader media)
{}
}
上面这个类扩展性差
找到其参数的共同类型,通过多态的形式,可以提高扩展性

class MyBufferRead extends MyReader
{
private MyReader r;
MyBufferReader(MyReader r)
{}
}

MyReader//专门用于读取数据的对象
|–MyTextReader
|–MyMediaReader
|–MyDataReader
|–MyBufferReader

装饰模式比继承要灵活,避免了继承体系的臃肿
而且降低了类与类之间的关系

装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能
所以装饰类和被装饰类通常都属于一个体系

完善后的MyBufferedReader

import java.io.*;class MyBufferedReader extends Reader{    private Reader r;    MyBufferedReader(Reader r)    {        this.r = r;    }    //可以一次读一行数据的方法    public String myReadLine()throws IOException    {        //定义一个临时容器,原BufferedReader中封装的是字符数组        //为了演示方便,定义一个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);        }        if(sb.length()!=0)            return sb.toString();        return null;    }/*覆盖Reader类中的抽象方法*/public int read(char[] cbuf,int off,int len)throws IOException{return r.read(cbuf,off,len);}public void close()throws IOException{r.close();}    public void myClose()throws IOException    {        r.close();    }}class MyBufferedReaderDemo{    public static void main(String[] args) throws IOException    {        FileReader fr = new FileReader("bufWriter_Copy.txt");        MyBufferedReader myBuf = new MyBufferedReader(fr);        String line = null;        while((line=myBuf.myReadLine())!=null)        {            System.out.println(line);        }        myBuf.myClose();    }LineNumberReader--------------------------------import java.io.*;class LineNumberReaderDemo{    public static void main(String[] args)    {        LineNumberReader lnr = null;        try        {            lnr = new LineNumberReader(new FileReader("PersonDemo.java"));            String line = null;            lnr.setLineNumber(100);//从100开始计数            while((line=lnr.readLine())!=null)            {                System.out.println(lnr.getLineNumber()+"::"+line);            }        }        catch(IOException e)        {            throw new RuntimeException("读取失败");        }        finally        {            try            {                if(lnr!=null)                    lnr.close();            }            catch(IOException e)            {                throw new RuntimeException("读取失败");            }        }    }}

这里写图片描述

自定义MyLineNumberReader

import java.io.*;class MyLineNumberReader extends MyBufferedReader{    private int lineNumber;    MyLineNumberReader(Reader r)    {        super(r);    }    public String myReadLine()throws IOException    {        lineNumber++;        return super.myReadLine();    }    public void setLineNumber(int lineNumber)    {        this.lineNumber = lineNumber;    }    public int getLineNumber()    {        return lineNumber;    }}/*class  MyLineNumberReader{    private Reader r;    private int lineNumber;    MyLineNumberReader(Reader r)    {        this.r = r;    }    public String myReadLine()    {        try        {            lineNumber++;            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);            }            if(sb.length()!=0)                return sb.toString();            return null;        }        catch(IOException e)        {            throw new RuntimeException("读取失败");        }    }    public void setLineNumber(int lineNumber)    {        this.lineNumber = lineNumber;    }    public int getLineNumber()    {        return lineNumber;    }    public void myClose()    {        try        {            if(r!=null)                r.close();        }        catch(IOException e)        {            throw new RuntimeException("读取关闭失败");        }    }}*/class MyLineNumberReaderDemo{    public static void main(String[] args) throws IOException    {        FileReader fr = new FileReader("CopyTestByBuf.java");        MyLineNumberReader mylnr = new MyLineNumberReader(fr);        String line = null;        while((line=mylnr.myReadLine())!=null)        {            System.out.println(mylnr.getLineNumber()+"::"+line);        }        mylnr.myClose();        /*        FileReader fr = null;        MyLineNumberReader mylnr = null;        try        {            fr = new FileReader("CopyTestByBuf.java");            mylnr = new MyLineNumberReader(fr);            String line = null;            //mylnr.setLineNumber(100);            while((line=mylnr.myReadLine())!=null)            {                System.out.println(mylnr.getLineNumber()+"::"+line);            }        }        catch(IOException e)        {            throw new RuntimeException("打印失败");        }        mylnr.myClose();        */    }}

这里写图片描述

被注释的部分是手写练习try{}catch(){}的,没有抛异常。演示注意要去掉继抛异常。

字节流

字符流:
FileReader
FileWriter

BufferedReader
BufferedWriter

字节流:
InputStream
OutputStream

需求:想要操作图片数据
这时就要用到字节流

import java.io.*;class FileStream{    public static void main(String[] args)throws IOException    {        //writeFile();        readFile_3();    }    public static void readFile_3()throws IOException    {        FileInputStream fis = new FileInputStream("fos.txt");        //int num = fis.available();//文件字节长度        //定义一个刚刚好的缓冲区,不用循环了        //慎用        byte[] buf = new byte[fis.available()];        fis.read(buf);        System.out.println(new String(buf));        fis.close();    }    public static void readFile_2()throws IOException    {        FileInputStream fis = new FileInputStream("fos.txt");        byte[] buf = new byte[1024];        int len = 0;        while((len=fis.read(buf))!=-1)        {            System.out.println(new String(buf,0,len));        }        fis.close();    }    public static void readFile_1()throws IOException    {        FileInputStream fis = new FileInputStream("fos.txt");        int ch = 0;        while((ch=fis.read())!=-1)        {            System.out.println((char)ch);        }        fis.close();    }    public static void writeFile()throws IOException    {        FileOutputStream fos = new FileOutputStream("fos.txt");        fos.write("abcde".getBytes());        fos.close();    }}

复制一个图片

思路:
1,用字节读取流对象和图片相关联
2,用字节写入流对象创建一个图片文件,用于存储获取到的图片数据。
3,通过循环读写,完成数据的存储。
4,关闭资源。

import java.io.*;class CopyPic{    public static void main(String[] args)    {        FileOutputStream fos = null;        FileInputStream fis = null;        try        {            fos = new FileOutputStream("c:\\2.jpg");            fis = new FileInputStream("c:\\1.jpg");            byte[] buf = new byte[1024];            int len = 0;            while((len = fis.read(buf))!=-1)            {                fos.write(buf,0,len);            }        }        catch(IOException e)        {            throw new RuntimeException("复制文件失败");        }        finally        {            try            {                if(fis!=null)                    fis.close();            }            catch(IOException e)            {                throw new RuntimeException("读取关闭失败");            }            try            {                if(fos!=null)                    fos.close();            }            catch(IOException e)            {                throw new RuntimeException("写入关闭失败");            }        }    }}

注意目录下是否有要复制的图片。

演示MP3的复制。通过缓冲区

BufferedOutputStream
BufferedInputStream

import java.io.*;class Copymp3{    public static void main(String[] args)throws IOException    {        long start = System.currentTimeMillis();        copy_1();        long end = System.currentTimeMillis();        System.out.println((end-start)+"毫秒");       }    //通过字节流的缓冲区完成复制    public static void copy_1()throws IOException    {        BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("c:\\1.mp3"));        BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\2.mp3"));        int by = 0;        while((by= bufis.read())!=-1)        {            bufos.write(by);        }        bufis.close();        bufos.close();    }}

自定义BufferedOutputStream方法

用此方法在Copymp3里演示发现复制的文件0KB
第一个字节打印的结果就是-1

11111111 11111111 11111111 11111111
00000000 00000000 00000000 11111111
———————————————————————————&
00000000 00000000 00000000 11111111

所以返回时&255,只保留低八位,前面补0
避免了第一个字节就是-1的情况,使文件正常写出。

import java.io.*;class MyBufferedInputStream{    private InputStream in;    private byte[] buf = new byte[1024];    private int pos = 0,count = 0;    MyBufferedInputStream(InputStream in)throws IOException    {        this.in = in;    }    public int myRead()    {        //通过in对象读取数据,并存储到buf中        if(count==0)        {            count = in.read(buf);            if(count<0)                return -1;            pos = 0;            byte b = buf[pos];            count--;            pos++;            return b&255;        }        else if(count>0)        {            byte b = buf[pos];            count--;            pos++;            return b&0xff;        }        return -1;    }    public void myClose()throws IOException    {        in.close();    }}

转换流

读取键盘录入

System.out:对应的是标准的输出设备 控制台
System.in:对应的是标准的输入设备 键盘

需求:
通过键盘录入数据
当录入一行数据后,就将该行数据进行打印
如果录入的数据是over,就停止录入

import java.io.*;class ReadIn{    public static void main(String[] args)throws IOException    {        InputStream in = System.in;        StringBuilder sb = new StringBuilder();        while(true)        {            int ch = in.read();            if(ch=='\r')                continue;            if(ch=='\n')            {                String s = sb.toString();                if("over".equals(s))                    break;                System.out.println(s.toUpperCase());                sb.delete(0,sb.length());            }            else                sb.append((char)ch);        }    }}

这里写图片描述
字节流:
FileInputStream
FileOutputStream

BufferedInputStream
BufferedOutputStream

通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理
也就是readLine方法

能不能直接使用readLine方法来完成一行数据的读取呢?

readLine方法是BufferedReader类中的方法
而键盘录入的read方法是字节流InputStream的方法

那么能不能将字节流转成字符流再使用字符流缓冲区的readLine方法呢?

InputStreamReader 是字节流通向字符流的桥梁

import java.io.*;class TransStreamDemo{    public static void main(String[] args)throws IOException    {        //获取键盘录入对象        //InputStream in = System.in;        //将字节流对象转成字符流对象,使用转换流。InputStreamReader        //InputStreamReader isr = new InputStreamReader(in);        //为了提高效率,将字符串进行缓冲区技术高效操作,使用BufferedReader        //BufferedReader bufr = new BufferedReader(isr);        //三句话变一句话        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));        //OutputStream out= System.out;        //OutputStreamWriter osw = new OutputStreamWriter(out);        //BufferedWriter bufw = new BufferedWriter(osw);        //三句话变一句话        BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));        String line = null;        while((line=bufr.readLine())!=null)        {            if("over".equals(line))                break;            bufw.write(line.toUpperCase());            bufw.newLine();            bufw.flush();        }        bufr.close();        bufw.close();    }

这里写图片描述
1,
源:键盘录入
目的:控制台

2,需求:想把键盘录入的数据存储到一个文件中。
源:键盘
目的:文件

3,需求:想要把一个文件的数据打印在控制台上
源:文件
目的:控制台

流操作的基本规律:
通过三个明确
1,源和目的
源:InputStream Reader
目的:OutputStream Writer
2,操作的数据是否是纯文本
是:字符流
不是:字节流

3,当体系明确后,再明确要使用哪个具体的对象
通过设备来进行区分:
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台

import java.io.*;class TransStreamDemo2{    public static void main(String[] args)throws IOException    {        //1        //BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));        //BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));        //2        //BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));        //BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("out.txt")));        //3        BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("out.txt")));        BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));        String line = null;        while((line=bufr.readLine())!=null)        {            if("over".equals(line))                break;            bufw.write(line.toUpperCase());            bufw.newLine();            bufw.flush();        }        bufr.close();        bufw.close();    }}

import java.io.*;import java.util.*;import java.text.*;class ExceptionInfoDemo{    public static void main(String[] args)    {        try        {            int[] arr = new int[2];            System.out.println(arr[3]);        }        catch(Exception e)        {            try            {                Date d = new Date();                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss");                String s = sdf.format(d);                PrintStream ps = new PrintStream("exception.log");                ps.println(s);                System.setOut(ps);            }            catch(IOException ex)            {                throw new RuntimeException("日志文件创建失败");            }            e.printStackTrace(System.out);        }    }}

log4j网络上用这个建立日至信息

import java.util.*;import java.io.*;class SystemInfo {    public static void main(String[] args)throws IOException    {        Properties prop = System.getProperties();        //System.out.println(prop);        prop.list(new PrintStream("sysinfo.txt"));    }}
0 0
原创粉丝点击