Java IO(一)

   字节流的两个基类:

  1. InputStream
  2. OutputStream

   字符流的两个基类:

  1. Reader
  2. Writer

   Writer

   先学习一下字符流的特点。

   既然IO流是用于操作数据的,那么数据的最常见体现形式是:文件。那么先以操作文件为主来演示。

   例,需求:在硬盘上,创建一个文件并写入一些文字数据。

   分析:

   找到一个专门用于操作文件的Writer子类对象——FileWriter,后缀名是父类名,前缀名是该流对象的功能

   步骤:

  1. 创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件。而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。其实该步骤就是在明确数据要存放的目的地。
  2. 调用write(),将字符串写入到流中。
  3. 刷新流对象中的缓冲区中的数据,将数据刷到目的地中。
  4. 关闭流资源,但是关闭之前会刷新一次内部的缓冲区中的数据。将数据刷到目的地中。和flush()区别:flush刷新后,流可以继续使用,close()刷新后,会将流关闭。   

   示例代码如下:

import java.io.FileWriter;
import java.io.IOException;

public class FileWriterDemo0 {

    public static void main(String[] args) throws IOException {
        //创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件
        //而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
        //其实该步骤就是在明确数据要存放的目的地。
        FileWriter fw = new FileWriter("demo.txt");
        
        //调用write(),将字符串写入到流中
        fw.write("abcde");
        
        //刷新流对象中的缓冲区中的数据,将数据刷到目的地中。
        //fw.flush();
        
        /*
         * 关闭流资源,但是关闭之前会刷新一次内部的缓冲区中的数据。
         * 将数据刷到目的地中。
         * 和flush()区别:flush刷新后,流可以继续使用,close()刷新后,会将流关闭。
         */
        fw.close();
        
        fw.write("haha");
    }

}

   IO异常的处理方式:

   示例代码:

/*
IO异常的处理方式。
最后无论如何都应关闭资源,所以应放在finally代码块中
*/
import java.io.FileWriter;
import java.io.IOException;

public class FileWriterDemo1 {

    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            fw = new FileWriter("demo.txt");
            fw.write("abcdefg");
        } catch (IOException e) {
            System.out.println("catch:" + e.toString());
        } finally {
            try {
                if(fw != null) 
                    fw.close();
            } catch (IOException e) {
                System.out.println(e.toString());
            }
        }
        
    }

}

   对已有文件的数据续写:

   示例代码:

/*
演示对已有文件的数据续写。
*/
import java.io.FileWriter;
import java.io.IOException;

public class FileWriterDemo2 {

    public static void main(String[] args) throws IOException {
        /*
         * 传递一个true参数,代表不覆盖已有的文件。
         * 并在已有文件的末尾处进行数据续写。
         * \r\n在windows中表示行终止符
         */
        FileWriter fw = new FileWriter("demo.txt", true);
        
        fw.write("nihao\r\nxiexie");
        
        fw.close();
    }

}

 

   Reader

   例,需求:从硬盘的一个文件中读取内容

   代码:

import java.io.FileReader;
import java.io.IOException;

public class FileReaderDemo0 {

    public static void main(String[] args) throws IOException {
        /*
         * 创建一个文件读取流对象,和指定名称的文件相关联。
         * 要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException。
         */
        FileReader fr = new FileReader("demo.txt");
        
        /*
         * 调用读取流对象的read()
         * read():一次读取一个字符,会自动往下读。
         */
        int ch = 0;
        while((ch = fr.read()) != -1) {
            System.out.println((char)ch);
        }
        /*
        while(true) {
            int ch = fr.read();
            if(ch == -1) 
                break;
            System.out.println("ch = " + (char) ch);
        }
        */
        
        fr.close();
    }

}

   图示:

 

   第二种方式:通过字符数组进行读取。

   示例代码如下:

/*
第二种方式:通过字符数组进行读取。
 */
import java.io.FileReader;
import java.io.IOException;

public class FileReaderDemo1 {

    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("demo.txt");
        
        /*
         * 定义一个字符数组,用于存储读到的字符
         * 该read(char[])返回的是读到的字符个数。
         */
        char[] buf = new char[1024];//字符数组大小为2KB
        
        int num = 0;
        while((num = fr.read(buf)) != -1) {
            System.out.println(new String(buf, 0, num));
        }
        
        fr.close();
    }

}

   图示:

   练习:读取一个.java文件,并打印在控制台上。

   代码如下:

import java.io.FileReader;
import java.io.IOException;

public class FileReaderTest {

    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("FileWriterDemo2.java");
        
        char[] buf = new char[1024];
        
        int num = 0;
        
        while((num = fr.read(buf)) != -1) {
            System.out.println(new String(buf, 0, num));
        }
        
        fr.close();
    }

}

   

   字符流缓冲区

   缓冲区的出现是为了提高流的操作效率而出现的,所以在创建缓冲区之前,必须要先有流对象。

   BufferedWriter

   该缓冲区中提供了一个跨平台的换行符:newLine()。

   示例代码如下:

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class BufferedWriterDemo {

    public static void main(String[] args) throws IOException {
        /*
         * 创建一个字符写入流对象
         */
        FileWriter fw = new FileWriter("buf.txt");
        /*
         * 为了提高字符写入流的效率,加入了缓冲区。
         * 只要将需要被提高效率的流对象作为参数,传递给缓冲区的构造函数即可。
         */
        BufferedWriter bufw = new BufferedWriter(fw);
        
        for(int i = 0; i < 5; i++) {
            bufw.write("abcde" + i);
            bufw.newLine();//bufw.write("\r\n")
            bufw.flush();//写一次刷新一次。
        }
        /*
         * 记住,只要用到缓冲区,就要刷新。
         */
        //bufw.flush();
        
        /*
         * 其实关闭缓冲区,就是在关闭缓冲区中的流对象。
         * 所以fw.close();就不用写了。
         */
        bufw.close();
        
        //fw.close();
    }

}

   BufferedReader

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

   readLine()方法返回的时候只返回回车符之前的数据内容,并不返回回车符(行终止符)。

   示例代码:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class BufferedReaderDemo0 {

    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.print(line);
        }
        
        bufr.close();
    }

}

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

   示例代码如下:

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

class MyBufferReader extends Reader {
    /*
    private FileReader fr = null;
    
    MyBufferReader(FileReader fr) {
        this.fr = fr;
    }
    */
    
    private Reader fr = null;
    
    MyBufferReader(Reader fr) {
        this.fr = fr;
    }
    
    /*
     * 可以一次读一行数据的方法
     */
    public String myReadLine() throws IOException {
        /*
         * 定义一个临时容器,原BufferReader封装的是一个字符数组
         * 为了演示方便,定义一个StringBuilder容器,因为最终还是要将数据变为字符串。
         */
        StringBuilder sb = new StringBuilder();
        int ch = 0;
        while((ch = fr.read()) != -1) {
            if(ch == '\r')
                continue;
            if(ch == '\n')
                return sb.toString();
            else 
                sb.append((char) ch);
        }
        if(sb.length() != 0) {//如果文本数据最后的行终止符故意去掉,那么StringBuilder里面还是有数据的 ,也要给予返回
            return sb.toString();
        }
        return null;//如果已到达流末尾,则返回 null
    }
    
    /*
     * 覆盖Reader类中的抽象方法。
     */
    @Override
    public void close() throws IOException {
        fr.close();
    }

    @Override
    public int read(char[] cbuf, int off, int len) throws IOException {
        return fr.read(cbuf, off, len);
    }
    
    public void myClose() throws IOException {
        fr.close();
    }

    
}
public class MyBufferReaderDemo {

    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("buf.txt");
        
        MyBufferReader myBuf = new MyBufferReader(fr);
        
        String line = null;
        
        while((line = myBuf.myReadLine()) != null) {
            System.out.println(line);
        }
        
        myBuf.myClose();
    }

}

   LineNumberReader

   一个带行号的缓冲区。

   示例代码如下:

import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;

public class LineNumberReaderDemo {

    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("PersonDemo.java");
        
        LineNumberReader lnr = new LineNumberReader(fr);
        
        String line = null;
        
        lnr.setLineNumber(100);//设置行号从100开始,实际打印是从101开始的
        
        while((line = lnr.readLine()) != null) {
            System.out.println(lnr.getLineNumber() + " " + line);
        }
        
        lnr.close();
    }

}

   练习:模拟一个带行号的缓冲区对象。

   代码:

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

class MyLineNumberReader extends MyBufferReader {
    private int lineNumber;//行号
    
    MyLineNumberReader(Reader r) {
        super(r);
    }
    
    public String myReadLine() throws IOException {
        
        lineNumber++;//myReadLine()方法读一次自增一次
        
        return super.myReadLine();
    }

    public int getLineNumber() {
        return lineNumber;
    }

    public void setLineNumber(int lineNumber) {
        this.lineNumber = lineNumber;
    }
    
}
/*
class MyLineNumberReader {
    private Reader r;
    private int lineNumber;//行号
    
    MyLineNumberReader(Reader r) {
        this.r = r;
    }
    
    public String myReadLine() throws IOException {
        
        lineNumber++;//myReadLine()方法读一次自增一次
        
        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 int getLineNumber() {
        return lineNumber;
    }

    public void setLineNumber(int lineNumber) {
        this.lineNumber = lineNumber;
    }
    
    public void myClose() throws IOException {
        r.close();
    }
    
}
*/
public class MyLineNumberReaderDemo {

    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("bufWriter_Copy.txt");
        
        MyLineNumberReader my = new MyLineNumberReader(fr);
        
        String line = null;
        
        //my.setLineNumber(100);
        
        while((line = my.myReadLine()) != null) {
            System.out.println(my.getLineNumber()+ " " +line);
        }
        
        my.myClose();
    }

}

   由此引出装饰设计模式

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

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

   举例说之:

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

class SuperPerson {
    private Person p = null;
    SuperPerson(Person p) {
        this.p = p;
    }
    public void superChifan() {
        System.out.println("开胃酒");
        p.chifan();
        System.out.println("甜点");
        System.out.println("来一根");
    }
}

public 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 {
    
    MyBufferReader(MyTextReader text) {
    
    }
    
    MyBufferReader(MyMediaReader media) {
    
    }
}
------------------------------------------------------------------
class MyBufferReader extends MyReader {
    private MyReader r;
    MyBufferReader(MyReader r) {
        
    }
    
}
MyReader//专门用于读取数据的类。
    |---MyTextReader(被装饰类)
    |---MyMediaReader(被装饰类)
    |---MyDataReader(被装饰类)
    |---MyBufferReader(装饰类)

   可知:

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

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

   

   练习:将c盘一个文本文件复制到d盘中。

   分析:

   复制原理:其实就是将c盘下的文件数据存储到d盘的一个文件中。

   步骤:

  1. 在d盘创建一个文件,用于存储c盘文件中的数据。
  2. 定义读取流和c盘文件关联。
  3. 通过不断的读写完成数据存储。
  4. 关闭资源。   

   代码:

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CoptTest {

    public static void main(String[] args) throws IOException {
        //copy_1();
        copy_2();
    }
    
    public static void copy_2() {
        FileWriter fw = null;
        FileReader fr = null;
        try {
            fw = new FileWriter("FileWriterDemo2_copy.java");
            fr = new FileReader("FileWriterDemo2.java");
            
            char[] buf = new char[1024];
            int len = 0;
            if((len = fr.read(buf)) != -1) {
                fw.write(buf, 0, len);
            }
        } catch (IOException e) {
            throw new RuntimeException("读写失败");
        } finally {
            if(fr != null)
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            if(fw != null)
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }
    /*
     * 从c盘读一个字符,就往d盘写一个字符
     */
    public static void copy_1() throws IOException {
        //创建目的地
        FileWriter fw = new FileWriter("FileWriterDemo2_copy.txt");
        
        //与已有文件关联
        FileReader fr = new FileReader("FileWriterDemo2.java");
        
        //
        int ch = 0;
        
        while((ch = fr.read()) != -1) {
            fw.write(ch);
        }
        
        fw.close();
        
        fr.close();
    }

}

   用缓冲区技术优化代码:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyTextByBuf {

    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("写入关闭失败");
                }
        }
    }

}

   图示:

 

posted @ 2016-03-11 21:23  叶十一少  阅读(289)  评论(0编辑  收藏  举报